【问题标题】:Python avoiding implementation method name clashes in subclassPython避免子类中的实现方法名称冲突
【发布时间】:2015-05-30 07:37:18
【问题描述】:

在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)的需求。

【问题讨论】:

标签: python inheritance


【解决方案1】:

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 方法是不可能的。

【讨论】:

  • 谢谢!看到您在子类中使用 __private 确认名称修饰将是防止我的子类无意中覆盖超类中的实现方法的适当方法。
  • 最好奇的输出是尝试teen._will_private_run_test() 看看函数_will_private_run_test 是否会调用parent__private 版本或teen 的版本。从这个答案的角度来看,我假设它会正确调用parent 的版本。
猜你喜欢
  • 2012-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多