Python: dynamically creating a class: overwrite elements

I have a python class hierarchy that I want to expand at runtime. In addition, each class in this hierarchy has a static "dict" attribute, which I want to rewrite in each subclass. Simplyfied looks like this:

'dict' is a protected (public but with leading underscore) member

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 

This works as expected. Now the question is: why does it no longer work if I declare a private attribute:

Now the same thing with "dict" being a private member

 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!? 

Suddenly, a subclass of C has the same values ​​in 'dict' as its superclass !?

Can anyone be so kind and explain to me what is the reason for this? Thanks in advance!

+4
source share
3 answers

phild, as you know, when you prefix an attribute name with an underscore __ , the python interpreter automatically changes the attribute name (mangles) from __attribute to _CLS__attribute , where CLS is the class name.

However when you say

return type(name, (cls, ), { '__dict' : {} })

keys in the dictionary { '__dict' : {} } will not be distorted. __dict remains unchanged.

Thus, D ends with both D._C__dict and 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 refers to an attribute of class C. Therefore, when you run

C.setval(1, 5)

you change D._C__dict as well as C._C__dict . They are one and the same.

+3
source

Here is the chapter in the documentation on the "private" attributes . And I commented on your class definition to make it more understandable:

 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'] 

those. all child objects have their own __dict attribute, but only one of the base class is used.

+2
source

The Java and C ++ concepts of "protected" and "private" do not apply. The Python naming convention does little, but not what you imagine.

__name does some name manipulation, which makes access difficult because the name is private.

Your _dict and __dict are just class level attributes that are simply shared by all class instances.

+1
source

All Articles