在python中创建子类时,如何确保我的子类实现方法不会无意中覆盖超类中的实现方法?我试图避免:
class A:
def a(self):
self._helper_func()
def _helper_func(self):
# do something specific to A
class B(A):
def b(self):
self._helper_func()
def _helper_func(self):
# do something; didn't realize this would mess up a()
我认为唯一的选择是:(1)阅读超类的源代码,以确保我选择一个唯一的子类方法名称(当超类更新时可能会中断);或者(2)在我的子类中的所有实现方法上使用__(通常__被描述为超类防止子类化的一种方式;但我认为它会帮助子类避免破坏超类)。
我在这里错过了什么吗?
更新 @sobolevn基本上回答了我的问题。澄清一下:我在名称修改过程中看到的所有讨论围绕着超级类试图隐藏/阻止他们的方法被调用/覆盖(并且通常会评论这是不是这样的python方式和用户应尊重单一领导_)。我关注的是对我没有编写的类进行子类化的非常不同的问题(并且本身没有使用名称修改),并为实现方法选择名称,这可能会无意中破坏代码中的代码。超类(或其父类),如果该名称已被使用。
基于我所读到的内容,在我看来,(a)编写我自己没有写过的类的子类的最佳实践是将__加到所有私有方法前面;但是(b)鉴于所有方法在python中都是虚拟的,而且我经常希望我的子类公开一些新的公共/受保护方法,所以没有好的选择来完全了解所有类使用的所有非破坏方法名称我继承了,这种意识可以避免担心(a)。
答案 0 :(得分:3)
PEP8说:
仅对非公共方法和实例使用一个前导下划线 变量
为避免与子类名称冲突,请使用两个前导下划线 调用Python的名称修改规则。
Python使用类名来破坏这些名称:如果类Foo有 名为__a的属性,Foo .__ a无法访问它。 (坚持不懈 用户仍然可以通过调用Foo._Foo__a获得访问权限。)通常, 双引导下划线应仅用于避免名称冲突 使用设计为子类的类中的属性。
它们之间有什么区别?看看这个例子:
class Parent(object):
""" This parent has all types of methods. """
def _will_private_run_test(self):
self.__private()
def public(self):
print('public', self.__class__)
def _protected(self):
print('protected', self.__class__)
def __private(self):
print('private', self.__class__)
class Child(Parent):
""" This child only knows parent's methods. """
pass
class ChildWithOverrides(Parent):
""" This child overrides all. """
def public(self):
print('New', 'public', self.__class__)
def _protected(self):
print('New', 'protected', self.__class__)
def __private(self):
print('New', 'private', self.__class__)
def run_private(obj):
if hasattr(obj, '__private'):
print('A mirracle happened!')
try:
obj.__private()
except AttributeError as ae:
print(ae)
parent = Parent()
parent._will_private_run_test()
child = Child()
teen = ChildWithOverrides()
parent.public()
child.public()
teen.public()
parent._protected()
child._protected()
teen._protected()
run_private(parent)
run_private(child)
run_private(teen)
输出将是:
('private', <class '__main__.Parent'>)
('public', <class '__main__.Parent'>)
('public', <class '__main__.Child'>)
('New', 'public', <class '__main__.ChildWithOverrides'>)
('protected', <class '__main__.Parent'>)
('protected', <class '__main__.Child'>)
('New', 'protected', <class '__main__.ChildWithOverrides'>)
'Parent' object has no attribute '__private'
'Child' object has no attribute '__private'
'ChildWithOverrides' object has no attribute '__private'
正如您所看到的,无法从外部调用__private方法。