python超级调用子方法

2024-10-03 11:15:56 发布

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

关于super()的用法有很多问题,但似乎没有一个能回答我的问题。

从子类调用super().__init__()时,超级构造函数中的所有方法调用实际上都是从子类中获取的。考虑以下类结构:

class A(object):
    def __init__(self):
        print("initializing A")
        self.a()
    def a(self):
        print("A.a()")

class B(A):
    def __init__(self):
        super().__init__()
        # add stuff for B
        self.bnum=3 # required by B.a()        
    def a(self):
        print("B.a(), bnum=%i"%self.bnum)

b=B()

失败的是

initializing A
Traceback (most recent call last):
  File "classmagic.py", line 17, in 
    b=B()
  File "classmagic.py", line 11, in __init__
    super().__init__()
  File "classmagic.py", line 5, in __init__
    self.a()
  File "classmagic.py", line 15, in a
    print("B.a(), bnum=%i"%self.bnum)
AttributeError: 'B' object has no attribute 'bnum'

在这里,我调用B()中的超级构造函数来初始化一些基本结构(其中一些结构作为自己的函数a()执行)。但是,如果我也重写a()函数,则在调用A的构造函数时使用此实现,该构造函数失败的原因是AB一无所知,并且可能使用不同的内部变量。

这可能是直观的,也可能不是直观的,但是当我希望A中的所有方法都只能访问在那里实现的函数时,我必须做什么?


Tags: 方法函数inpyselfinitdefline
3条回答

考虑这个电话:

class B(A):
    def __init__(self):
        A.__init__(self)

这就是当您调用super().__init__()时发生的情况。这反过来又调用self.a(),这当然是类B的函数a,而不是A,因为self是类B。正如Martijn所说,您可以使用双下划线名称,或者显式地使用类名,但否则就不可能从超类调用重写的方法。

您需要使用A.a(self),而不是调用self.a()。但是对于一个特定类上的所有方法,这并不常见,而且您应该重新评估B是否应该继承自A

如果代码调用无法重写的特定私有方法,请使用以两个下划线开头的名称:

class A(object):
    def __init__(self):
        print("initializing A")
        self.__a()
    def __a(self):
        print("A.a()")

class B(A):
    def __init__(self):
        super().__init__()
        # add stuff for B
        self.bnum=3 # required by B.a()        
    def __a(self):
        print("B.__a(), bnum=%i"%self.bnum)

Python"mangles"通过在类名(加下划线)中添加这样的方法名,以尽量减少子类用自己的版本覆盖它们的可能性。

PEP 8 Python Style Guide有这样一个关于私名损坏的说法:

If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores. This invokes Python's name mangling algorithm, where the name of the class is mangled into the attribute name. This helps avoid attribute name collisions should subclasses inadvertently contain attributes with the same name.

Note 1: Note that only the simple class name is used in the mangled name, so if a subclass chooses both the same class name and attribute name, you can still get name collisions.

Note 2: Name mangling can make certain uses, such as debugging and __getattr__(), less convenient. However the name mangling algorithm is well documented and easy to perform manually.

Note 3: Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers.

相关问题 更多 >