我有一个python类层次结构,我想在运行时扩展。此外,此层次结构中的每个类都有一个静态属性“dict”,我想在每个子类中覆盖它。简化它看起来像这样:
class A(object):
_dict = {}
@classmethod
def getdict(cls):
return cls._dict
@classmethod
def setval(cls, name, val):
cls._dict[name] = val
@classmethod
def addchild(cls, name):
return type(name, (cls, ), { '_dict' : {} })
B = A.addchild('B')
A.setval(1, 5)
print A.getdict()
# prints: {1: 5}
# like expected
print B.getdict()
# prints: {}
# like expected
这与预期一样有效。现在的问题是:如果我将属性声明为private,为什么它不再起作用:
class C(object):
__dict = {}
@classmethod
def getdict(cls):
return cls.__dict
@classmethod
def setval(cls, name, val):
cls.__dict[name] = val
@classmethod
def addchild(cls, name):
return type(name, (cls, ), { '__dict' : {} })
D = C.addchild('D')
C.setval(1, 5)
print C.getdict()
# prints: {1: 5}
# like expected
print D.getdict()
# prints: {1: 5}
# why!?
突然D
,C
的子类,在'dict'中与其超类具有相同的值!?
有人可以这么善良并向我解释,原因是什么?提前谢谢!
答案 0 :(得分:3)
phild,如您所知,当您使用双下划线__
为属性名称添加前缀时,python解释器会自动将(mangles)属性名称从__attribute
更改为_CLS__attribute
,其中CLS是班级名称。
然而,当你说
时 return type(name, (cls, ), { '__dict' : {} })
字典{ '__dict' : {} }
中的键不会被破坏。 __dict
保持不变。
因此,D最终同时使用D._C__dict
和D.__dict
:
(Pdb) dir(D)
['_C__dict', '__class__', '__delattr__', '__dict', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'addchild', 'getdict', 'setval']
D._C__dict
指的是C的class属性。所以当你运行
C.setval(1, 5)
您正在更改D._C__dict
以及C._C__dict
。他们是同一个。
答案 1 :(得分:2)
这是chapter in documentation about "private" attributes。我对你的课程定义进行了评论,使其更清晰:
class C(object):
__dict = {} # This creates C.__dict__['_C__dict']
@classmethod
def getdict(cls):
return cls.__dict # Uses cls.__dict__['_C__dict']
@classmethod
def setval(cls, name, val):
cls.__dict[name] = val # Uses cls.__dict__['_C__dict']
@classmethod
def addchild(cls, name):
return type(name, (cls, ), { '__dict' : {} }) # Creates child.__dict__['__dict']
即。所有子项都有自己的__dict
属性,但只使用了一个基类。
答案 2 :(得分:1)
“受保护”和“私有”的Java或C ++概念不适用。命名约定Python做了一点,但不是你想象的。
__name
会进行一些名称修改,因为名称被遮挡而难以访问。
您的_dict
和__dict
只是类级属性,只是所有类的实例共享。