super().method()与super(self.\u class\uuuu,self).method()之间的区别

2024-05-07 22:14:10 发布

您现在位置:Python中文网/ 问答频道 /正文

这是我想写的代码:

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". 

有人能解释为什么吗?


Tags: no代码selfnewobjectfooinitbind
1条回答
网友
1楼 · 发布于 2024-05-07 22:14:10

调用super()时,不应使用self.__class__type(self)

在Python 3中,对super()的无参数调用相当于super(B, self)(在类B的方法内);注意类的显式命名。Python编译器将一个__class__闭包单元添加到使用super()的方法中,这些方法没有引用正在定义的当前类的参数(请参见Why is Python 3.x's super() magic?)。

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

总之,在Python 3中:

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

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

等于:

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

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

但你应该使用前者,因为它可以省去你重复的时间。

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

对于您的bind_foo()方法,您必须传入一个显式类,从中搜索MRO,因为Python编译器无法在这里确定绑定新替换项时使用的类foo

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__(no self)让Python为您提供闭包单元,但这是对A的引用,而不是这里的C。当绑定新的foo时,您希望在MRO中搜索重写的方法开始在C进行搜索。

请注意,如果您现在创建一个类D,从C创建子类,那么就会再次出现问题,因为现在您正在调用bind_foo(),并以D而不是C作为起点依次调用super()。那么,最好的方法是用一个显式的类引用调用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的类定义中直接定义的一样。

注意,在这里调用super()上的bind_foo()是没有意义的;您没有在这里重写它,所以您可以只调用self.bind_foo()

相关问题 更多 >