Python, Overriding an inherited class method
我有两个班,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Field( object ): def __init__( self, a, b ): self.a = a self.b = b self.field = self.buildField() def buildField( self ): field = [0,0,0] return field class Background( Field ): def __init__( self, a, b, c ): super(Background, self).__init__( a, b ) self.field = self.buildField( c ) def buildField( self, c ): field = [c] return field a, b, c = 0, 1, 2 background = Background( a, b, c ) |
此错误指向字段的
1 | "TypeError: buildField() takes exactly 2 arguments (1 given)." |
我希望先调用background init()。要将"a,b"传递给field s in it(),field将分配a和b,然后将一个包含三个0的列表分配给field。然后让background的init()继续,然后调用它自己的buildField()并用包含c的列表覆盖self.field。
似乎我不完全理解super(),但是在查看了Web和周围类似的继承问题之后,我找不到解决问题的方法。
我期望C++这样的行为,其中一个类可以重写继承的方法。我如何才能做到这一点或类似的事情。
我发现大多数与此相关的问题都是人们使用双下划线。我对super继承的经验是使用继承的类init()将不同的变量传递给super类。不涉及覆盖任何内容。
I expected Background init() to be called. To pass"a, b" to Fields
init(), Field to assign a and b
到目前为止,一切都很好。
then to assign a list with three 0's
in it to field.
啊。这就是我们得到错误的地方。
1 | self.field = self.buildField() |
虽然这条线出现在
由于
1 | self.field = self.buildField() |
引发错误。
那么,我们如何告诉python调用
名称管理(用双下划线命名属性)的目的是解决这个确切的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Field(object): def __init__(self, a, b): self.a = a self.b = b self.field = self.__buildField() def __buildField(self): field = [0,0,0] return field class Background(Field): def __init__(self, a, b, c): super(Background, self).__init__(a, b) self.field = self.__buildField(c) def __buildField(self, c): field = [c] return field a, b, c = 0, 1, 2 background = Background(a, b, c) |
方法名称
1 | self.field = self.__buildField() |
调用
1 | self.field = self.__buildField(c) |
在
从C++的角度来看,这里可能存在两个误解。
首先,重写具有不同签名的方法不会像C++那样重载它。如果您的一个后台对象试图在不带参数的情况下调用buildField,则不会调用字段的原始版本——它已完全隐藏。
第二个问题是,如果在超类中定义的方法调用buildField,则将调用子类版本。在Python中,所有的方法都是动态绑定的,就像C++ EDCOX1×25的方法一样。
字段的
I expected Background init() to be called
实际上,
但是看看你的背景课……
1 2 3 4 | class Background( Field ): def __init__( self, a, b, c ): super(Background, self).__init__( a, b ) self.field = self.buildField( c ) |
因此,
现在在你的现场课上:
1 2 3 4 5 6 7 | class Field( object ): def __init__( self, a, b ): print self.__class__ // Prints `<class '__main__.Background'>` self.a = a self.b = b self.field = self.buildField() |
您的
这就是你出错的原因。
The error"TypeError: buildField() takes exactly 2 arguments (1
given).
因为你没有传递任何值。因此,唯一传递的值是隐式
1 2 3 4 | def __init__( self, a, b ): self.a = a self.b = b self.field = self.buildField() |
在
似乎您的代码应该更好地编写为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Field( object ): def __init__( self, a, b ): self.a = a self.b = b self.field = Field.buildField() @classmethod def buildField(cls): field = [0,0,0] return field class Background( Field ): def __init__( self, a, b, c ): super(Background, self).__init__(a, b) self.field = Background.buildField(c) @classmethod def buildField(cls,c): field = [c] return field a, b, c = 0, 1, 2 background = Background( a, b, c ) |
如果您不能让基本构造函数完成,那么它就表示设计有缺陷。
因此,如果必须在构造函数中调用这些方法,那么最好使用
但是,如果基类构造函数没有从内部调用任何实例方法,则可以安全地覆盖该基类的任何方法。
说的是
而且这听起来像是写得过火了:
让我解释一下:
名为field的属性将初始化为
[0,0,0] 。@property 装饰工看起来更合适。然后,
Background 类重写了这个属性。
快速而肮脏的解决方案
我不知道您的业务逻辑,但有时通过传递super class的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #!/usr/bin/env python class Field( object ): def __init__( self, a, b ): self.a = a self.b = b self.field = self.buildField() def buildField( self ): field = [0,0,0] return field class Background( Field ): def __init__( self, a, b, c ): # super(Background, self).__init__( a, b ) # Unfortunately you should repeat or move initializing a and b # properties here self.a = a self.b = b self.field = self.buildField( c ) def buildField( self, c ): # You can access super class methods assert super(Background, self).buildField() == [0,0,0] field = [c] return field a, b, c = 0, 1, 2 bg = Background(a,b,c) assert bg.field == [2] |
使用属性
有更清晰的语法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #!/usr/bin/env python class Field( object ): @property def field(self): return [0,0,0] def __init__( self, a, b ): self.a = a self.b = b class Background( Field ): def __init__( self, a, b, c ): super(Background, self).__init__( a, b ) self.c = c assert (self.a, self.b, self.c) == (0,1,2) # We assigned a and b in # super class's __init__ method assert super(Background, self).field == [0,0,0] assert self.field == [2] @property def field(self): return [self.c] a, b, c = 0, 1, 2 background = Background( a, b, c ) print background.field |