提问人:aviro 提问时间:10/31/2017 最后编辑:jonrsharpeaviro 更新时间:4/26/2020 访问量:2461
继承带有双下划线的类属性
Inheriting class attribute with double underscore
问:
我想我理解 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()
这是我得到的输出:
Class name is Base, data is Base
Class name is A, data is Base
Class name is B, data is Base
现在,我了解到对于每个类,类属性的实际名称被修改为 .例如,对于 Base,它将是 ,对于 A,它将是 ,等等。_<Class name>__data
_Base__data
_A__data
我的问题是,在它内部正确标识了继承类(Base、A 和 B)的名称,但总是导致 .为什么?我的意思是,如果是 A 或 B,那么我知道我属于 A 或 B 类,所以我希望分别成为 A 或 B 类之一。我在这里错过了什么?func
cls.__data
cls._Base__data
__name__
cls.__data
答:
你并没有“失踪”,相反,你只是“发现”了名称修改的作用:它是为了确保方法内带有双下划线的变量将始终看到与该方法在同一类中定义的属性,并且不在其子类中。
如果您只想使用该属性,因为它在每个子类中被覆盖,这是所有其他属性的正常行为,但对于以两个下划线为前缀的属性。
因此,在编译时,内部使用的名称本身被篡改为 ..__data
func
_base__data
OrderedDict
Python 的集合。OrderedDict 有一个额外的陷阱:Python 既提供了一个纯 python 实现,它使用 the 作为其“私有属性”,如上所述,但也有一个 C 语言的原生代码实现,以及不向 Python 公开的私有结构。__
该模块用以下几行结束 OrderedDict 代码块:collections
try:
from _collections import OrderedDict
except ImportError:
# Leave the pure Python version in place.
pass
也就是说:正常的“集合。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__',
...
]
评论
if you know what you are doing
正如您所注意到的,用于名称更改的名称是声明方法的类的名称,而不是当前对象的派生类型。
此功能的文档显式地给出了一个示例,说明如何保护变量免受派生类(而不是使用实例变量的外部代码)的影响。
名称修改有助于让子类在不中断类内方法调用的情况下重写方法。例如:
class Mapping: def __init__(self, iterable): self.items_list = [] self.__update(iterable) def update(self, iterable): for item in iterable: self.items_list.append(item) __update = update # private copy of original update() method class MappingSubclass(Mapping): def update(self, keys, values): # provides new signature for update() # but does not break __init__() for item in zip(keys, values): self.items_list.append(item)
评论
'_Base'