python超级调用子方法

thi*_*ias 5 python oop superclass

关于使用的问题有很多,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()
Run Code Online (Sandbox Code Playgroud)

失败了

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'
Run Code Online (Sandbox Code Playgroud)

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

这可能是也可能不直观,但当我希望所有方法A只能访问那里实现的功能时,我该怎么做?

Mar*_*ers 5

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

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)
Run Code Online (Sandbox Code Playgroud)

Python 通过添加类名称(加上下划线)来“破坏”此类方法名称,以最大程度地降低子类用其自己的版本覆盖它们的机会。

PEP 8 Python的风格指南是这样说的关于私人名字改编:

如果您的类打算被子类化,并且您具有不希望使用子类的属性,请考虑使用双引号和下划线来命名它们。这将调用Python的名称修改算法,其中将类的名称修改为属性名称。这有助于避免属性名称冲突,如果子类无意中包含相同名称的属性。

注1:请注意,整齐的名称中仅使用简单的类名,因此,如果子类同时选择了相同的类名和属性名,则仍会发生名称冲突。

注意2:名称修饰可以使某些用途(如调试和 __getattr__())变得不太方便。但是,名称处理算法已被详细记录,并且易于手动执行。

注意3:并非每个人都喜欢名称修饰。尝试在避免意外名称冲突和高级呼叫者可能使用名称之间取得平衡。