and*_*db. 44 python methods inheritance overwrite super
我有两节课,Field和Background.他们看起来有点像这样:
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 )
Run Code Online (Sandbox Code Playgroud)
这个错误指向Field的buildField():
"TypeError: buildField() takes exactly 2 arguments (1 given)."
Run Code Online (Sandbox Code Playgroud)
我期望首先调用Background init().要将"a,b"传递给Fields init(),要将字段分配给a和b,然后将其中包含三个0的列表分配给字段.然后为后台的init()继续,然后调用它自己的buildField()并使用包含c的列表覆盖self.field.
我似乎并不完全理解super(),但是在查看网络上和周围的类似继承问题后,我无法找到解决问题的方法.
我期望像c ++这样的行为,其中一个类可以覆盖一个继承的方法.我怎样才能实现这一点或类似的东西.
我发现与此相关的大多数问题都是使用双下划线的人.我使用super继承的经验是使用继承的类init()将不同的变量传递给超类.什么都不涉及覆盖任何东西.
unu*_*tbu 43
我期望调用Background init().要将"a,b"传递给Fields init(),将Field传递给a和b
到现在为止还挺好.
然后将一个包含三个0的列表分配给字段.
啊.这是我们得到错误的地方.
self.field = self.buildField()
Run Code Online (Sandbox Code Playgroud)
即使这一行发生在其中Field.__init__,self也是一个实例Background.这样self.buildField的发现Background的buildField方法,而不是Field的.
因为Background.buildField需要2个参数而不是1个,
self.field = self.buildField()
Run Code Online (Sandbox Code Playgroud)
引发错误.
那么,我们如何告诉Python调用Field的buildField方法,而不是Background的?
目的名称重整(命名有双下划线的属性)是解决这一确切的问题.
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)
Run Code Online (Sandbox Code Playgroud)
方法名称__buildField被"修改"到_Field__buildField内部,Field所以在里面Field.__init__,
self.field = self.__buildField()
Run Code Online (Sandbox Code Playgroud)
调用self._Field__buildField(),这是Field的__buildField方法.同样地,
self.field = self.__buildField(c)
Run Code Online (Sandbox Code Playgroud)
内部Background.__init__调用Background的__buildField方法.
Ian*_*and 23
从C++的角度来看,这里可能存在两个误解.
首先,覆盖具有不同签名的方法不会像在C++中那样使其重载.如果您的一个Background对象尝试调用不带参数的buildField,则不会调用Field的原始版本 - 它已被完全隐藏.
第二个问题是,如果超类中定义的方法调用buildField,则将调用子类版本.在python中,所有方法都是动态绑定的,就像C++ virtual方法一样.
Field __init__期望处理一个没有参数的buildField方法的对象.您将该方法与具有buildField方法的对象一起使用一个参数.
事实super是它不会改变对象的类型,所以你不应该改变超类'方法可能调用的任何方法的签名.
Roh*_*ain 17
我期望调用Background init()
实际上Background init()被称为..
但是看看你的Background类..
class Background( Field ):
def __init__( self, a, b, c ):
super(Background, self).__init__( a, b )
self.field = self.buildField( c )
Run Code Online (Sandbox Code Playgroud)
所以,第一个语句__init__是调用super class(Field)init方法..并传递selfas参数..现在这self实际上是一个引用Background class...
现在你的Field类: -
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()
Run Code Online (Sandbox Code Playgroud)
你的buildField()方法实际上是调用Background类中的那个.这是因为,self这里是Backgroundclass的实例(self.__class__在你的__init__方法中尝试打印Field class).当你在调用__init__方法时传递它,从Background类...
这就是你收到错误的原因..
错误"TypeError:buildField()只需要2个参数(给定1个).
因为你没有传递任何值..所以,只传递的值是隐含的self.
遗嘱super(Background, self).__init__( a, b )将调用:
def __init__( self, a, b ):
self.a = a
self.b = b
self.field = self.buildField()
Run Code Online (Sandbox Code Playgroud)
在Field。但是,selfhere 指的是background实例,self.buildField()实际上是调用buildField(),Background这就是您收到该错误的原因。
看来您的代码应该更好地编写为:
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 )
Run Code Online (Sandbox Code Playgroud)
如果您不能让基本构造函数完成,则表明设计有缺陷。
因此,如果您必须在构造函数中调用这些方法,最好使用装饰器或来区分buildField()属于该类。classmethodstaticmethod
但是,如果您的基类构造函数不从内部调用任何实例方法,则您可以安全地覆盖该基类的任何方法。
| 归档时间: |
|
| 查看次数: |
59097 次 |
| 最近记录: |