5

关于使用的问题有很多,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()时使用此实现,该构造函数失败,因为对它一无所知并且可能使用不同的内部变量。AAB

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

4

4 回答 4

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)

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

PEP 8 Python 样式指南对私有名称修改有这样的说法:

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

注意 1:请注意,重命名中只使用了简单的类名,因此如果子类选择相同的类名和属性名,仍然会出现名称冲突。

注意 2:名称修饰可以使某些用途,例如调试和 __getattr__(),不太方便。然而,名称修饰算法有据可查,并且易于手动执行。

注 3:不是每个人都喜欢名字修饰。尝试在避免意外名称冲突的需要与高级呼叫者的潜在使用之间取得平衡。

于 2012-09-18T13:42:37.880 回答
3

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

于 2012-09-18T13:45:02.857 回答
0

考虑这个调用:

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

这就是你打电话时发生的事情super().__init__()。这反过来又调用了,这当然是 classself.a()的功能,而不是因为is of class 。正如 Martijn 所说,您可以使用双下划线名称,或显式使用类名,但否则无法从超类调用覆盖的方法。aBAselfB

于 2012-09-18T13:47:26.123 回答
0

如果我们通过以下实例化步骤B

  • 我们称super(B,self).__init__,即A.__init__
  • 它调用self.a(),也就是说,B.a()在我们的例子中,
  • 哪个使用self.bnum

除了bnum尚未定义...所以,AttributeError

对于这种特殊情况,在调用之前bnum定义您的in就足够了B.__init__ super(B,self).__init__

class B(A):
    def __init__(self):
       self.bnum=3
       super(B, self).__init__()

在进行名称修改的黑暗、黑暗路径之前,您可能只想花时间组织子类的代码:应该在父类之前执行,以初始化一些特殊变量,还是父类之后执行,以替换一些默认值?

于 2012-09-18T13:49:39.557 回答