Domanda

Ho una gerarchia di classi pitone, che voglio estendere in fase di esecuzione. Inoltre ogni classe in questa gerarchia ha un attributo 'dict' statica, che voglio sovrascrivere in ogni sottoclasse. Simplyfied assomiglia a questo:

'dict' è un membro protetto (pubblico ma con sottolineatura)

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

Questo funziona esattamente come previsto. La domanda ora è: perché doesnt funziona più se dichiaro l'attributo privato:

Ora la stessa cosa con 'dict' 'essere un utente privato

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

Improvvisamente D, la sottoclasse di C, ha gli stessi valori in 'dict' come la sua superclasse!?

si poteva essere così gentile e spiegare a me, quale sia la ragione di questo è? Grazie in anticipo!

È stato utile?

Soluzione

phild, come si sa, quando si prefisso un nome di attributo con doppia sottolineatura __, l'interprete Python cambia automagicamente (Mangani) attribuiscono nome da __attribute a _CLS__attribute, dove CLS è il nome della classe.

Tuttavia, quando si dice

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

le chiavi nel dizionario { '__dict' : {} } non ottengono straziati. __dict rimane lo stesso.

Così D finisce con entrambi D._C__dict e 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 riferisce alla classe di attributo C. Così, quando si esegue

C.setval(1, 5)

si sta modificando D._C__dict così come C._C__dict. Essi sono la stessa cosa.

Altri suggerimenti

Ecco un capitolo nella documentazione su "privato" attributi . E ho commentato voi definizione di classe per renderlo più chiaro:

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

vale a dire. tutti hanno il loro bambino attributo __dict, ma è usato solo uno dalla classe base.

non si applicano i concetti Java o C ++ di "protetto" e "privato". La convenzione di denominazione Python fa un po ', ma non quello che stai immaginando.

Il __name fa qualche nome mangling, rendendo difficile l'accesso perché il nome è oscurata.

Il tuo _dict e __dict sono semplicemente gli attributi a livello di classe che sono semplicemente condivisi da tutte le istanze delle classi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top