用双下划线继承类属性

avi*_*iro 2 python inheritance

我想我理解 python 中“名称修改”的概念,但我可能错过了一些东西。看看下面的代码:

#!/usr/bin/env python

class Base(object):
    __data = "Base"

    @classmethod
    def func(cls):
        return "Class name is {}, data is {}".format(cls.__name__, cls.__data)


class A(Base):
    __data = "A"


class B(A):
    __data = "B"


print Base.func()
print A.func()
print B.func()
Run Code Online (Sandbox Code Playgroud)

这是我得到的输出:

Class name is Base, data is Base
Class name is A, data is Base
Class name is B, data is Base
Run Code Online (Sandbox Code Playgroud)

现在,我明白对于每个类,类属性的实际名称被修改为_<Class name>__data. 例如,对于 Base 来说是_Base__data,对于 A 来说是_A__data,等等。

我的问题是,在func它内部正确标识了继承类的名称(Base、A 和 B),但cls.__data总是导致cls._Base__data. 这是为什么?我的意思是,如果__name__是 A 或 B,那么我知道我在 A 类或 B 类中,所以我希望cls.__data分别成为 A 或 B 中的一个。我在这里缺少什么?

jsb*_*eno 6

您并没有“丢失”,相反,您只是“发现”了名称修饰的作用:它是为了确保方法内具有双下划线的变量将始终看到与该方法在同一类中定义的属性,并且在没有它的子类。

如果您只是想使用在每个子类中被覆盖的属性,这是所有其他属性的正常行为,但对于以两个下划线为前缀的属性。

因此,发生的情况是.__data内部使用的名称func本身在编译时被损坏为_base__data.

有序字典

Python 的 collections.OrderedDict 有一个额外的陷阱:Python 提供了纯 Python 实现,__如上所述,它使用了作为其“私有属性”的暴露于 Python。

collections模块以这些行结束 OrderedDict 代码块:

try:
    from _collections import OrderedDict
except ImportError:
    # Leave the pure Python version in place.
    pass
Run Code Online (Sandbox Code Playgroud)

也就是说:正常的“collections.OrderedDict”是用C 编写的,有很多不透明的结构,子类无法利用。

访问 Python 定义的 OrderedDict 的唯一方法是删除_collections.OrderedDict属性(在_collections,而不是collections模块中),然后重新加载collections模块。

如果你这样做,并实例化一个有序的字典,私有数据结构可能看起来是:


from imp import reload
import _collections, collections
backup = _collections.OrderedDict
del _collections.OrderedDict
collections = reload(collections)
PyOrderedDict = collections.OrderedDict
_collections.OrderedDict = backup
a  = PyOrderedDict()
dir(a)

Out[xx]: 
['_OrderedDict__hardroot',
 '_OrderedDict__map',
 '_OrderedDict__marker',
 '_OrderedDict__root',
 '_OrderedDict__update',
 '__class__',
 '__contains__',
 '__delattr__',
 ...
]
Run Code Online (Sandbox Code Playgroud)