关于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
的构造函数时会使用此实现,因为A
对B
一无所知并且可能使用不同的内部A
变量
这可能是也可能不直观,但当我希望{{1}}中的所有方法只能访问在那里实现的功能时,我该怎么做?
答案 0 :(得分: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 "mangles"这样的方法名称通过添加类名(加上下划线)来最小化子类用自己的版本覆盖它们的机会。
PEP 8 Python Style Guide有关于私人名称修改的说法:
如果您的类要进行子类化,并且您具有属性 您不希望子类使用,请考虑使用它们命名 双引导下划线和没有尾随下划线。这会调用 Python的名称修改算法,其中类的名称是 被破坏成属性名称。这有助于避免属性名称 碰撞应该是子类无意中包含的属性 同名。
注1:请注意,在错位中只使用简单的类名 name,所以如果子类选择相同的类名和属性 名字,你仍然可以得到名字冲突。
注2:名称修改可以进行某些用途,例如调试和
__getattr__()
,不太方便。但是名称为mangling算法 有详细记录,易于手动执行。注3:不是每个人都喜欢名字错误。尝试平衡需要 避免意外姓名冲突,可能会被高级来电者使用。
答案 1 :(得分:2)
您需要使用self.a()
,而不是致电A.a(self)
。但是对于特定类的所有方法并不常见,您应该重新评估B
是否应该继承A
。
答案 2 :(得分:0)
考虑这个电话:
class B(A):
def __init__(self):
A.__init__(self)
当您致电super().__init__()
时会发生这种情况。反过来,这会调用self.a()
,这当然是a
类的函数B
,而不是A
,因为self
属于B
类}。正如Martijn所说,你可以使用双下划线名称,或明确使用类名,但是否则不可能从超类中调用重写方法。
答案 3 :(得分:0)
如果我们完成B
的实例化步骤:
super(B,self).__init__
,即A.__init__
self.a()
,即B.a()
,self.bnum
除了bnum
尚未定义...所以,AttributeError
。
对于这种特殊情况,只需在bnum
之前定义B.__init__
,然后再调用super(B,self).__init__
class B(A):
def __init__(self):
self.bnum=3
super(B, self).__init__()
在走向黑暗,黑暗的名称修剪路径之前,您可能只想花时间组织子类的代码:如果在之前执行,则初始化一些特殊变量或在之后的,以替换一些默认值?