Pregunta

Tengo una jerarquía de clases de Python que quiero ampliar en tiempo de ejecución.Además, cada clase en esta jerarquía tiene un atributo estático 'dict' que quiero sobrescribir en cada subclase.Simplificado se ve así:

'dict' es un miembro protegido (público pero con guión bajo inicial)

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

Esto funciona tal como se esperaba.La pregunta ahora es:¿Por qué ya no funciona si declaro el atributo privado?

Ahora pasa lo mismo con 'dict' como miembro privado.

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

De repente D, la subclase de C, tiene los mismos valores en 'dict' que su superclase!?

¿Alguien podría ser tan amable y explicarme cuál es el motivo de esto?¡Gracias de antemano!

¿Fue útil?

Solución

Phild, como sabes, cuando antepones un nombre de atributo con doble guión bajo __, el intérprete de Python cambia automáticamente (destroza) el nombre del atributo de __attribute a _CLS__attribute, donde CLS es el nombre de la clase.

Sin embargo, cuando dices

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

las claves en el diccionario { '__dict' : {} } no te dejes destrozar. __dict sigue siendo el mismo.

Así D termina con ambos D._C__dict y 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 se refiere al atributo de clase de C.Entonces cuando corres

C.setval(1, 5)

estas cambiando D._C__dict así como C._C__dict.Son uno y lo mismo.

Otros consejos

Aquí está una capítulo en la documentación acerca de "privado" atributos . Y te comento definición de clase para que sea más claro:

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

es decir. todas niño tienen su propio atributo __dict, pero sólo uno de la clase base se utiliza.

El Java o conceptos de "protegido" y "privado" C ++ no se aplican. La convención de nombres de Python hace un poco, pero no te lo estás imaginando.

El __name hace algún renombrado de nombres, lo que hace difícil el acceso porque el nombre es oscurecida.

Su _dict y __dict son simplemente atributos de nivel de clase que simplemente están compartidos por todas las instancias de las clases.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top