Python,重写继承的类方法

and*_*db. 44 python methods inheritance overwrite super

我有两节课,FieldBackground.他们看起来有点像这样:

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的发现BackgroundbuildField方法,而不是Field的.

因为Background.buildField需要2个参数而不是1个,

self.field = self.buildField()
Run Code Online (Sandbox Code Playgroud)

引发错误.


那么,我们如何告诉Python调用FieldbuildField方法,而不是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方法.

  • 回答我自己的问题,用户“super().buildField()”。 (3认同)
  • 使用"受损"方法作为公共方法,我认为这不是一个好主意. (2认同)

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.


K Z*_*K Z 5

遗嘱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

但是,如果您的基类构造函数不从内部调用任何实例方法,则您可以安全地覆盖该基类的任何方法。