__init__是一种类方法吗?

thi*_*dam 8 python inheritance multiple-inheritance python-2.7

我正在研究Python的超级方法和多重继承.我读到的东西就像当我们使用super来调用一个在所有基类中都有实现的基本方法时,即使有各种参数,也只会调用一个类的方法.例如,

class Base1(object):
    def __init__(self, a):
        print "In Base 1"

class Base2(object):
    def __init__(self):
        print "In Base 2"

class Child(Base1, Base2):
    def __init__(self):
        super(Child, self).__init__('Intended for base 1')
        super(Child, self).__init__()# Intended for base 2
Run Code Online (Sandbox Code Playgroud)

这产生TyepError了第super一种方法.super会调用它首先识别的方法实现,TypeError而不是检查其他类.但是,当我们执行以下操作时,这将更加清晰并且正常工作:

class Child(Base1, Base2):
    def __init__(self):
        Base1.__init__(self, 'Intended for base 1')
        Base2.__init__(self) # Intended for base 2
Run Code Online (Sandbox Code Playgroud)

这导致两个问题:

  1. __init__方法的静态方法或类方法?
  2. 为什么要使用super,它隐式选择自己的方法,而不是像后一个例子那样显式调用方法?它看起来比使用super更清洁.那么使用super第二种方式的优点是什么(除了使用方法调用编写基类名称)

Sin*_*ion 12

super()面对多重继承,尤其是存在的方法object 可能会有点棘手.一般规则是,如果使用super,则层次结构中的每个类都应使用super.处理此问题的一个好方法__init__是使每个方法都采用**kwargs,并始终在任何地方使用关键字参数.到调用object.__init__发生时,所有参数都应该弹出!

class Base1(object):
    def __init__(self, a, **kwargs):
        print "In Base 1", a
        super(Base1, self).__init__()

class Base2(object):
    def __init__(self, **kwargs):
        print "In Base 2"
        super(Base2, self).__init__()

class Child(Base1, Base2):
    def __init__(self, **kwargs):
        super(Child, self).__init__(a="Something for Base1")
Run Code Online (Sandbox Code Playgroud)

请参阅链接文章,了解有关其工作原理以及如何使其适用的更多说明!

编辑:冒着回答两个问题的风险,"为什么要使用超级?"

我们有super()许多的我们有类和继承同样的原因,对于模块化和提取我们的代码的工具.在类的实例上操作时,您不需要知道该类如何实现的所有细节,您只需要知道它的方法和属性,以及您打算如何使用该公共接口为了上课.特别是,您可以确信类的实现中的更改不会导致您作为其实例的用户出现问题.

从基类派生新类型时,同样的论点也成立.您不希望或不必担心这些基类的实现方式.这是一个具体的例子,说明如何不使用super可能出错.假设你有:

class Foo(object):
     def frob(self):
         print "frobbign as a foo"
class Bar(object):
     def frob(self):
         print "frobbign as a bar"
Run Code Online (Sandbox Code Playgroud)

你做了一个子类:

class FooBar(Foo, Bar):
    def frob(self):
        Foo.frob(self)
        Bar.frob(self)
Run Code Online (Sandbox Code Playgroud)

一切都很好,但是你意识到,当你开始它时, Foo真的是一种Bar,所以你改变它

 class Foo(Bar):
     def frob(self):
         print "frobbign as a foo"
         Bar.frob(self)
Run Code Online (Sandbox Code Playgroud)

哪个都很好,除了你的派生类,FooBar.frob()调用Bar.frob() 两次.

这是super()解决的确切问题,它可以保护您不止一次调用超类实现(当按照指示使用时...)


Bre*_*arn 9

至于你的第一个问题,__init__既不是静态方法,也不是类方法; 它是一种普通的实例方法.(也就是说,它接收实例作为其第一个参数.)

至于你的第二个问题,如果你想显式调用多个基类实现,那么就像你所做的那样明确地执行它确实是唯一的方法.但是,你似乎误解了如何super运作.当你打电话时super,它不会"知道"你是否已经打过电话.你调用super(Child, self).__init__Base1实现的两个调用,因为那是"最近的父"(最直接的超类Child).

你可以使用super,如果你想打电话只是这直接超类的实现.如果超类也被设置为调用其超类,那么你会这样做,依此类推.使用的方法super是让每个类只调用类层次结构中的下一个实现"up",这样super调用序列总体上按正确的顺序调用需要调用的所有内容.这种类型的设置通常称为"合作继承",您可以在线找到有关它的各种文章,包括此处此处.