super()。method()与super(self .__ class __,self).method()之间的区别

时间:2013-11-04 20:01:48

标签: python class inheritance

这是我试图编写的代码:

class A(object):
    def bind_foo(self):
        old_foo = self.foo
        def new_foo():
            old_foo()
            #super().foo()
            super(self.__class__,self).foo()

        self.foo = new_foo

    def __init__(self):
        print("A __init__")          

    def foo(self):
        print("A foo")

class B(A):
    def __init__(self):
        print("B __init__")
        super().__init__()

    def foo(self):
        print("B foo")
        super().foo()

class C(A):
    def __init__(self):
        print("C __init__")
        super().__init__()
        super().bind_foo()

    def foo(self):
        print("C foo")    

b  = B()
b.foo()

c = C()
c.foo()

B类和A类是预期的行为,也就是说,当我致电b.foo()时,它会调用a.foo()以及super()。 C类试图模仿子B和父A行为,但这次我不想明确地将super().foo()放在子类中,但我仍然希望调用父foo()。它按预期工作。

然而,我不明白的是,在A.bind_foo下,我必须使用super(self.__class__,self).foo()而不是super().foosuper().foo给出了

"SystemError: super(): no arguments". 

有人可以解释为什么会这样吗?

1 个答案:

答案 0 :(得分:17)

在致电self.__class__时,

在Python 3中,对不带参数的type(self)的调用等同于super()(在类super()上的方法中);请注意类的显式命名。 Python编译器将super(B, self)闭包单元添加到使用B而不带参数的方法(请参阅Why is Python 3.x's super() magic?),该参数引用正在定义的当前类

如果使用__class__super(),当子类尝试调用该方法时,您将遇到无限递归异常;那时super(self.__class__, self) 派生类,而不是原始类。见When calling super() in a derived class, can I pass in self.__class__?

总而言之,在Python 3中:

super(type(self), self)

等于:

self.__class__

但你应该使用前者,因为它可以让你自己重复。

在Python 2中,您只能使用第二种形式

对于你的class B(A): def __init__(self): print("B __init__") super().__init__() def foo(self): print("B foo") super().foo() 方法,你必须传入一个显式类来从中搜索MRO,因为Python编译器在这里无法确定绑定新替换时使用的是哪个类{{1 }}:

class B(A):
    def __init__(self):
        print("B __init__")
        super(B, self).__init__()

    def foo(self):
        print("B foo")
        super(B, self).foo()

可以使用bind_foo()(没有foo)让Python为你提供闭包单元格,但这是对def bind_foo(self, klass=None): old_foo = self.foo if klass is None: klass = type(self) def new_foo(): old_foo() super(klass, self).foo() self.foo = new_foo 的引用,这里没有__class__。当您绑定新的self时,您希望在MRO中搜索重写的方法,而不是开始在A进行搜索。

请注意,如果您现在创建一个类C,从foo进行子类化,则会再次出现错误,因为现在您正在调用C并在以D而不是C作为起点,转而致电bind_foo()。您最好的选择是使用显式类引用来调用super()。这里D(没有C)会做得很好:

bind_foo()

现在,您具有与不带参数的__class__相同的行为,对当前类的引用(您在其中定义方法self.的引用)将被传递到class C(A): def __init__(self): print("C __init__") super().__init__() self.bind_foo(__class__) ,使super()的行为就像直接在__init__的类定义中定义一样。

请注意,在此处super()调用new_foo()是没有意义的;您没有在此处覆盖它,因此您只需拨打C即可。