Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 2.7 无法调用超类的重写setter属性_Python 2.7_Inheritance_Properties - Fatal编程技术网

Python 2.7 无法调用超类的重写setter属性

Python 2.7 无法调用超类的重写setter属性,python-2.7,inheritance,properties,Python 2.7,Inheritance,Properties,我试图使用python属性和继承,但有些东西的行为并不直观。我希望能够利用继承类的属性getter和setter来避免重复行为所需的代码 为了简化我的问题,我创建了以下示例。我有一辆车,当给定一定数量的乘客时(使用乘客属性getter和setter),它可以计算乘客数量并填充汽车座椅。对于一辆有3排座位的货车,我应该只需要定义第3排座位的行为,并遵循前2排继承的汽车类别 class Car(object): def __init__(self): #Store vehi

我试图使用python属性和继承,但有些东西的行为并不直观。我希望能够利用继承类的属性getter和setter来避免重复行为所需的代码

为了简化我的问题,我创建了以下示例。我有一辆车,当给定一定数量的乘客时(使用乘客属性getter和setter),它可以计算乘客数量并填充汽车座椅。对于一辆有3排座位的货车,我应该只需要定义第3排座位的行为,并遵循前2排继承的汽车类别

class Car(object):
    def __init__(self):

        #Store vehicle passengers in a dictionary by row
        # - by default we'll have 1 in the front seat and 1 in the back
        self._contents = {'row1': 1,
                          'row2': 1}

    @property
    def occupants(self):
        """
        Number of occupants in the vehicle
        """

        #Get the number of people in row 1
        row1 = self._contents['row1']
        #Get the number of people in row 2
        row2 = self._contents['row2']
        return row1 + row2

    @occupants.setter
    def occupants(self, val):

        #Start with an empty car
        self._contents['row1'] = 0
        self._contents['row2'] = 0

        #Check to see whether there are more than 2 people entering the car
        if val > 2:
            #Put 2 in the front seats
            self._contents['row1'] = 2

            #Put the rest in the back seat - no matter how many there are!
            self._contents['row2'] = val - 2
        else:
            #Since there are 2 or fewer people, let them sit in the front
            self._contents['row1'] = val


class Van(Car):
    def __init__(self):
        super(Van, self).__init__()

        #Van's have an additional 3rd row
        self._contents['row3'] = 1

    @property
    def occupants(self):

        #Number of people in first 2 rows
        first_2_rows = super(Van, self).occupants
        #Number of people in 3rd row
        row3 = self._contents['row3']

        #Total number of people
        return first_2_rows + row3

    @occupants.setter
    def occupants(self, val):

        #Start with an empty van (Car class handles row1 and row2)
        self._contents['row3'] = 0

        #Check if there are more than 4 people entering the van
        if val > 4:
            #Put all but 4 folks in the back row
            self._contents['row3'] = val - 4

            #Load the first 2 rows in the same manner as for a car
            #This causes an AttributeError
            super(Van, self).occupants = 4
        else:
            #This causes an AttributeError
            super(Van, self).occupants = val

if __name__ == '__main__':

    van = Van()

    print "Van has {0} people".format(van.occupants)

    print "Seating 6 people in the van..."
    van.occupants = 6

    print "Van has {0} people".format(van.occupants)
我得到的结果如下:

Van has 3 people
Seating 6 people in the van...

Traceback (most recent call last):
  File "C:/scratch.py", line 74, in <module>
    van.occupants = 6
  File "C:/scratch.py", line 65, in occupants
    super(Van, self).occupants = 4
AttributeError: 'super' object has no attribute 'occupants'

Process finished with exit code 1
Van有3个人
车里坐着6个人。。。
回溯(最近一次呼叫最后一次):
文件“C:/scratch.py”,第74行,在
货车乘客=6
文件“C:/scratch.py”,第65行,第1行
超级(厢式货车,自卸车)。乘员=4
AttributeError:“超级”对象没有属性“占用者”
进程已完成,退出代码为1
我特别感兴趣的是,超类的getter工作得很好,但是当我尝试使用setter时,我得到了属性错误。我是否错误地使用了
super()
?有更好的方法吗

我的实际应用程序涉及在文本文件格式和类似字典的数据结构之间进行读/写。文本文件中的一些内容由我的基类解析出来,其他一些特殊参数由子类处理。在子类setter中,我想首先让基类从文本文件(填充数据结构)中解析它需要的任何内容,然后让子类解析出额外的值以存储在继承的数据结构中

一些研究将我引向并最终将它声明为一个“特性”而不是一个bug。因此,有没有一种方法可以使用属性和继承使上述逻辑工作?我必须使用
Car.acculations.fset(self,4)
还是什么?我可能会在一分钟内回答自己的问题,但我会继续发帖与大家分享。对不起,如果是重复的

编辑: 修正了一些额外的错误,如在设置乘员之前清空所有座椅,并且厢式车乘员设置器中的数字逻辑错误且不完整(只有在属性错误被修复后才变得明显)。

如您所述

。。。超文本的语义。。。仅适用于 代码属性,而不是数据属性

因此,解决方法是调用代码属性,而不是数据属性。这意味着,在本例中,您需要保留对setter方法的引用;让我们称之为
set\u
。所以不是

@occupants.setter
def occupants(self, val):
使用

而不是
super(…).accumbers=4
,您调用super的方法:

super(Van, self).set_occupants(4)

屈服

Van has 3 people
Seating 6 people in the van...
Van has 6 people

要继续使用@property decorator,但仍然能够从
super
调用setter,并且不必手动添加大量额外属性,您可以使用元类来完成这项工作。类装饰器也是可能的,但元类的优点是只需将其定义为
Car
的元类一次,然后元类及其行为由
Car
的所有子类继承,而类装饰器必须手动应用于每个子类



环顾网络,我发现
SomeClass.property.fset(self,value)
可以用来调用属性的setter。在本例中,SomeClass是Car(Van的超类),self是当前的Van实例,Car-acculations setter对其进行操作以填充Van的前2行(就像汽车一样)

输出为:

Van has 3 people
Seating 6 people in van1
Seating 2 people in van2
van1 has 6 people
van2 has 2 people
这方面的大量工作和演示也可以通过属性函数或元类来解决。我还不确定哪种方法更优雅,因为每种方法都有赞成和反对的


如果在这种情况下回答我自己的问题是不好的形式,请给我打电话,我会很乐意做任何必要的事情来遵循社区协议。

如果使用属性装饰器,有没有办法参考setter?我在十几个类中有几十个带有docstring的属性,我不想通过重构以后继承的属性来折射所有内容或创建不一致的样式。我看到了一种方法,但它使用了一个元类来实现结果(通过添加getter、setter、deleter属性,无论何时
Car
的子类是用属性定义的。我编辑了这篇文章来展示如何。哇,从来没有想过为类似的东西破坏元类…使用
Car.acculator.fset(self,4)让它工作起来)
。我的代码中还有一些不相关的错误…我会继续发布我得到的。感谢您在这方面所做的工作-如果您想使用属性.fset()更新您的答案解决方案如果这是更好的礼节,我可以将你的答案标记为答案。我现在已经接受了我自己的答案,因为这是我一直在寻找的解决方案类型,尽管我不知道哪一种更优雅或更“pythonic”。我可以建议一种不同的方式来选择我们的两种解决方案吗?对于单一继承,我们的两种解决方案将表现相同。但是如果您的类层次结构具有或曾经将具有多重继承,则使用一个以上使用
Someclass.property
的解决方案(续…)
Van has 3 people
Seating 6 people in the van...
Van has 6 people
class MetaCar(type):
    def __init__(cls, name, bases, clsdict):
        super(MetaCar, cls).__init__(name, bases, clsdict)
        for name, val in clsdict.items():
            if isinstance(val, property):
                setattr(cls, 'get_{}'.format(name), val.fget)
                setattr(cls, 'set_{}'.format(name), val.fset)
                setattr(cls, 'del_{}'.format(name), val.fdel) 

class Car(object):
    __metaclass__ = MetaCar

    def __init__(self):

        #Store vehicle passengers in a dictionary by row
        # - by default we'll have 1 in the front seat and 1 in the back
        self._contents = {'row1': 1,
                          'row2': 1}
    @property
    def occupants(self):
        """
        Number of occupants in the vehicle
        """

        #Get the number of people in row 1
        row1 = self._contents['row1']
        #Get the number of people in row 2
        row2 = self._contents['row2']
        return row1 + row2

    @occupants.setter
    def occupants(self, val):

        #Check to see whether there are more than 2 people entering the car
        if val > 2:
            #Put 2 in the front seats
            self._contents['row1'] = 2

            #Put the rest in the back seat - no matter how many there are!
            self._contents['row2'] = val - 2
        else:
            #Since there are 2 or fewer people, let them sit in the front
            self._contents['row1'] = val


class Van(Car):
    def __init__(self):
        super(Van, self).__init__()

        #Van's have an additional 3rd row
        self._contents['row3'] = 1

    @property
    def occupants(self):

        #Number of people in first 2 rows
        first_2_rows = super(Van, self).occupants
        #Number of people in 3rd row
        row3 = self._contents['row3']

        #Total number of people
        return first_2_rows + row3

    @occupants.setter
    def occupants(self, val):

        #Check if there are more than 4 people entering the van
        if val > 4:
            #Put all but 4 folks in the back row
            self._contents['row3'] = val - 4

        #Load the first 2 rows in the same manner as for a car
        super(Van, self).set_occupants(4)


if __name__ == '__main__':
    van = Van()

    print "Van has {0} people".format(van.occupants)

    print "Seating 6 people in the van..."
    van.occupants = 6

    print "Van has {0} people".format(van.occupants)
class Car(object):
    def __init__(self):

        #Store vehicle passengers in a dictionary by row
        # - by default we'll have 1 in the front seat and 1 in the back
        self._contents = {'row1': 1,
                          'row2': 1}

    @property
    def occupants(self):
        """
        Number of occupants in the vehicle
        """

        #Get the number of people in row 1
        row1 = self._contents['row1']
        #Get the number of people in row 2
        row2 = self._contents['row2']
        return row1 + row2

    @occupants.setter
    def occupants(self, val):

        #Start with an empty car
        self._contents['row1'] = 0
        self._contents['row2'] = 0

        #Check to see whether there are more than 2 people entering the car
        if val > 2:
            #Put 2 in the front seats
            self._contents['row1'] = 2

            #Put the rest in the back seat - no matter how many there are!
            self._contents['row2'] = val - 2
        else:
            #Since there are 2 or fewer people, let them sit in the front
            self._contents['row1'] = val


class Van(Car):
    def __init__(self):
        super(Van, self).__init__()

        #Van's have an additional 3rd row
        self._contents['row3'] = 1

    @property
    def occupants(self):

        #Number of people in first 2 rows
        first_2_rows = super(Van, self).occupants
        #Number of people in 3rd row
        row3 = self._contents['row3']

        #Total number of people
        return first_2_rows + row3

    @occupants.setter
    def occupants(self, val):

        #Start with an empty van (first 2 rows handled by Car class)
        self._contents['row3'] = 0

        #Check if there are more than 4 people entering the van
        if val > 4:
            #Put all but 4 folks in the back row
            self._contents['row3'] = val - 4

            #Load the first 2 rows in the same manner as for a car
            Car.occupants.fset(self, 4)
        else:
            #Load the first 2 rows in the same manner as for a car
            Car.occupants.fset(self, val)


if __name__ == '__main__':

    van1 = Van()
    van2 = Van()

    print "Van has {0} people".format(van1.occupants)

    print "Seating 6 people in van1"
    van1.occupants = 6

    print "Seating 2 people in van2"
    van2.occupants = 2

    print "van1 has {0} people".format(van1.occupants)
    print "van2 has {0} people".format(van2.occupants)
Van has 3 people
Seating 6 people in van1
Seating 2 people in van2
van1 has 6 people
van2 has 2 people