2013-10-24 12 views
5

Dire che ho una classe che definisce __slots__:Can __setattr __() può essere definito in una classe con __slots__?

class Foo(object): 
    __slots__ = ['x'] 

    def __init__(self, x=1): 
     self.x = x 

    # will the following work? 
    def __setattr__(self, key, value): 
     if key == 'x': 
      object.__setattr__(self, name, -value) # Haha - let's set to minus x 

posso definire __setattr__() per questo?

Dal Foo non dispone di __dict__, cosa aggiornerà?

risposta

9

Tutto il codice fa, oltre a negare il valore, è chiamare la classe genitore __setattr__, che è esattamente ciò che accadrebbe senza il tuo metodo __setattr__. Quindi la risposta breve è: Certo, puoi definire un __setattr__.

Quello che non si può fare è ridefinire __setattr__ usare self.__dict__, perché le istanze di una classe con slot Non hanno un attributo __dict__. Ma tali istanze do hanno un attributo self.x, il suo contenuto non è memorizzato in un dizionario nell'istanza.

Invece, i valori di slot sono memorizzati nella stessa posizione in cui un dizionario di istanza __dict__ sarebbe altrimenti memorizzato; sull'heap dell'oggetto. Lo spazio è riservato ai riferimenti len(__slots__) e descriptors alla classe accede a questi riferimenti per tuo conto.

Così, in un gancio __setattr__, si può chiamare tali descrittori direttamente invece:

def __setattr__(self, key, value): 
    if key == 'x': 
     Foo.__dict__[key].__set__(self, -value) 

deviazione Interessante: sì, sulle classi, senza un attributo __slots__, c'è è un descrittore, che vi darà l'accesso alla __dict__ oggetto di istanze:

>>> class Bar(object): pass 
... 
>>> Bar.__dict__['__dict__'] 
<attribute '__dict__' of 'Bar' objects> 
>>> Bar.__dict__['__dict__'].__get__(Bar(), Bar) 
{} 

che è come normali casi possono guardare su self.__dict__. Che ti fa chiedere dove si trova l'oggetto Bar.__dict__. In Python, è turtles all the way down, ci si guarda che oggetto sul type oggetto, naturalmente:

>>> type.__dict__['__dict__'] 
<attribute '__dict__' of 'type' objects> 
>>> type.__dict__['__dict__'].__get__(Bar, type) 
dict_proxy({'__dict__': <attribute '__dict__' of 'Bar' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None}) 
+0

fa __dict__ lavorare qui? è perché l'indirizzo effettivo di __dict__ e degli elementi dell'heap è lo stesso, e questa è una specie di uovo di Pasqua? o intendevi __slots__? –

+0

@CorleyBrigman: non confondere il '__dict__' della ** classe ** con quella dell'istanza ** **. Le istanze della classe 'Foo' non hanno un attributo' __dict__'. –

+0

@CorleyBrigman: E le istanze di 'Foo' non hanno attributo' __dict__', perché 'Foo .__ dict __ ['__ dict __'] 'genera un' KeyError'. –

Problemi correlati