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
只能访问那里实现的功能时,我该怎么做?
如果您的代码必须调用无法覆盖的特定私有方法,请使用以两个下划线开头的名称:
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:并非每个人都喜欢名称修饰。尝试在避免意外名称冲突和高级呼叫者可能使用名称之间取得平衡。