Python中私有和受保护方法的继承

2024-06-01 14:46:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道,Python中没有真正的私有/受保护方法。这种方法并不意味着隐藏任何东西;我只想了解Python的功能。

class Parent(object):
    def _protected(self):
        pass

    def __private(self):
        pass

class Child(Parent):
    def foo(self):
        self._protected()   # This works

    def bar(self):
        self.__private()    # This doesn't work, I get a AttributeError:
                            # 'Child' object has no attribute '_Child__private'

那么,这种行为是否意味着“受保护”的方法将被继承,但“私有”根本不会?
还是我错过了什么?


Tags: 方法self功能childobjectfoodefbar
3条回答

Python没有隐私模型,没有C++、C或java等访问修改器。没有真正的“受保护”或“私有”属性。

带有前导双下划线且没有尾随双下划线的名称将被损坏,以防止在继承时发生冲突。子类可以定义自己的__private()方法,这些方法不会干扰父类上的相同名称。这些名称被认为是类私有的;它们仍然可以从类外部访问,但不太可能意外冲突。

通过在任何这样的名称前面添加一个额外的下划线和类名(不管名称是如何使用的或是否存在),可以有效地为它们提供一个名称空间。在Parent类中,任何__private标识符(在编译时)都被名称_Parent__private替换,而在Child类中,标识符则被_Child__private替换,在类定义中无处不在。

以下操作将起作用:

class Child(Parent):
    def foo(self):
        self._protected()

    def bar(self):
        self._Parent__private()

请参阅词法分析文档中的Reserved classes of identifiers

__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.

以及引用的documentation on names

Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam occurring in a class named Ham will be transformed to _Ham__spam. This transformation is independent of the syntactical context in which the identifier is used.

不要使用类的私有名,除非你特别想避免告诉那些想给你的类分类的开发人员,他们不能使用特定的名称或者有破坏你的类的危险。除了已发布的框架和库之外,这个特性几乎没有用处。

PEP 8 Python Style Guide有这样一句话是关于私有名称损坏的:

If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores. This invokes Python's name mangling algorithm, where the name of the class is mangled into the attribute name. This helps avoid attribute name collisions should subclasses inadvertently contain attributes with the same name.

Note 1: Note that only the simple class name is used in the mangled name, so if a subclass chooses both the same class name and attribute name, you can still get name collisions.

Note 2: Name mangling can make certain uses, such as debugging and __getattr__(), less convenient. However the name mangling algorithm is well documented and easy to perform manually.

Note 3: Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers.

还有PEP8

Use one leading underscore only for non-public methods and instance variables.

To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.

Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.

按照惯例,你也应该远离_such_methods。我的意思是你应该把它们当作private

double__属性更改为_ClassName__method_name,这使得它比_method_name所隐含的语义隐私更为私有。

从技术上讲,如果你真的愿意,你仍然可以做到这一点,但可能没有人会这么做,因此出于代码抽象的维护原因,该方法在这一点上可能是私有的。

class Parent(object):
    def _protected(self):
        pass

    def __private(self):
        print("Is it really private?")

class Child(Parent):
    def foo(self):
        self._protected()

    def bar(self):
        self.__private()

c = Child()
c._Parent__private()

这还有一个额外的好处(或者说是主要的好处),就是允许一个方法不与子类方法名冲突。

相关问题 更多 >