__init__是一种类方法吗?

时间:2015-02-18 06:30:36

标签: python python-2.7 inheritance multiple-inheritance

我正在研究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

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

class Child(Base1, Base2):
    def __init__(self):
        Base1.__init__(self, 'Intended for base 1')
        Base2.__init__(self) # Intended for base 2

这导致两个问题:

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

2 个答案:

答案 0 :(得分:12)

面对多重继承,

super(),尤其是object can get a bit tricky上存在的方法。一般规则是,如果您使用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")

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

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

由于我们有类和继承的许多相同原因,我们有super(),作为模块化和抽象代码的工具。在一个类的实例上运行时,你不需要知道该类的实现方式的所有细节,你只需要知道它的方法和属性,以及你的意思如何使用该类的公共接口。特别是,您可以确信类的实现中的更改不会导致您作为其实例的用户出现问题。

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

class Foo(object):
     def frob(self):
         print "frobbign as a foo"
class Bar(object):
     def frob(self):
         print "frobbign as a bar"

你做了一个子类:

class FooBar(Foo, Bar):
    def frob(self):
        Foo.frob(self)
        Bar.frob(self)

一切都很好,但是当你意识到这一点时,你意识到 Foo确实是一种Bar,所以你改了它

 class Foo(Bar):
     def frob(self):
         print "frobbign as a foo"
         Bar.frob(self)

除了在您的派生类中,FooBar.frob()调用Bar.frob() 两次之外,其他都没问题。

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

答案 1 :(得分:9)

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

至于你的第二个问题,如果你想显式地调用多个基类实现,那么就像你一样明确地执行它确实是唯一的方法。但是,您似乎误解了super的工作原理。当你致电super时,如果你已经打过电话,它就不会“知道”。您对super(Child, self).__init__的两次调用都会调用Base1实现,因为这是“最近的父级”(Child的最直接的超类)。

如果要调用 这个直接的超类实现,可以使用super。如果超类也被设置为调用其超类,那么你会这样做,依此类推。使用super的方法是让每个类只调用类层次结构中的下一个实现“up”,以便super调用整个调用所有需要调用的内容,在右边订购。这种类型的设置通常称为“合作继承”,您可以在线找到有关它的各种文章,包括herehere