2012-01-29 9 views
6

Nota: Parte di un'implementazione peso mosca con Pythonquello che fa `super()` in `__new__`

import weakref 

class CarModel: 
    _models = weakref.WeakValueDictionary() 

    def __new__(cls, model_name, *args, **kwargs): 
     model = cls._models.get(model_name) 
     if not model: 
      model = super().__new__(cls) 
      cls._models[model_name] = model  
     return model 

    def __init__(self, model_name, air=False): 
     if not hasattr(self, "initted"): 
      self.model_name = model_name 
      self.air = air 
      self.initted=True 

Domanda 1> cosa vuol super() significa? Significa la classe genitore di CarModel?

Domanda 2> Ho anche difficoltà a capire i come la funzione __new__ opere? Nello specifico, la seguente riga.

model = super().__new__(cls) 

Descrizione di __new__:

Il funzione costruttore viene chiamato __new__ anziché __init__ e accetta esattamente un argomento, la classe che si sta costruendo (si viene chiamato prima che l'oggetto sia costruito, quindi non c'è l'argomento self ). Deve anche restituire l'oggetto appena creato.

+1

@Ben, basato sul [documento] (http://docs.python.org/py3k/reference/datamodel.html # objects-values-and-types), '__new __()' restituisce un'istanza di 'cls'. perché il codice 'model = super() .__ new __ (cls) ' in OP può creare un'istanza di 'cls'? In che modo la super classe di CarModel sa come creare un'istanza della sua sottoclasse? – q0987

+2

Questa sarebbe una grande domanda SO da sola (se non è già stata richiesta). La risposta breve è che passi la classe corrente con il parametro 'cls'. In definitiva, non c'è assolutamente modo di creare una nuova istanza senza rimandare completamente a 'object .__ new__', perché Python non ha istruzioni per" allocare un'istanza ". Ma 'object .__ new__' sa di creare un'istanza della classe passata (che sarà anche un'istanza di' object', perché tutto è un'istanza di 'object'). – Ben

risposta

1

super() viene utilizzato per fare riferimento alla superclasse (ovvero la classe genitore da cui si sta sottoclasse).

__new__ è un metodo che viene richiamato per creare una nuova istanza della classe, se definito.

+0

In 'super (class1, class2)', in che modo 'super' usa' class1' e 'class2'? – Adrian

1

credo, che si sta utilizzando python3, dove il super non ha bisogno di essere fornite con lo stesso nome della classe. Super si riferisce alle classi di base della classe corrente e fa il corretto Method Resolution Order per di richiamare il metodo dalla classe base giusta. __new__ è il metodo che viene richiamato per creare un'istanza. È lo first step in the instance creation.

+0

In 'super (class1, class2)', in che modo 'super' usa' class1' e 'class2'? – Adrian

11

Cominciando super() in sé è semplicemente un'abbreviazione per super(A, B), dove A è la classe in cui si verifica il codice e B è il primo argomento della funzione in cui si verifica il codice; Quindi nel tuo caso particolare, super().__new__(cls) espande a super(CarModel, cls).__new__(cls).

A sua volta, super(T, O) restituisce un "superoggetto". Per capire cosa fa un superoggetto, devi capire come funzionano i riferimenti di attributo su istanze e classi in Python.

assumendo alcun __getattr__ o __getattribute__ metodi sono coinvolti, referenziare attributo A su un oggetto O (cioè, valutando O.A o getattr(O, "A")) procede attraverso le seguenti fasi:

  1. Se "A" è definita esempio O s' dict (O.__dict__), allora il valore che dict è riportato direttamente, proprio come è.
  2. In caso contrario, ciascuna delle classi nell'ordine di risoluzione dei metodi di O viene verificata a turno, cercando "A" in ciascuno dei propri dict. Se trovato, chiama il valore D.
  3. Se D, a sua volta, non definisce un __get__, quindi viene restituito così com'è.Se lo fa, però, quindi D viene definito come un "descrittore", e il suo metodo __get__ è chiamato con O come primo argomento, e type(O) come secondo argomento.

Un riferimento attributo per una classe funziona sullo stesso, sostituendo il riferimento essendo classe per l'istanza, con le seguenti differenze:

  • Fase 1 non si applica.
  • Procedimento __get__ è chiamato con None come primo argomento, e la classe essendo fatto riferimento come secondo.

Python utilizza descrittori per implementare cose come metodi di istanza, metodi di classe, metodi statici e proprietà.

Un super oggetto creato con super(T, O), poi, è un oggetto (built-in) con un metodo __getattribute__ che è chiamato ad ogni attributo di riferimento su di esso, e cerca l'attributo nelle dicts delle uniche classi seguenti T nel MRO di O. Il valore che trova poi, chiama __get__ come al solito.

il processo è un po 'complessa, così come un esempio, ecco come avrebbe funzionato sul vostro caso specifico. Poiché CarModel è definito così com'è, il suo MRO è [CarModel, object].

  1. super().__new__(cls) si espande a super(CarModel, cls).__new__(cls), come descritto sopra.
  2. super(CarModel, cls) viene valutata per produrre un super oggetto S.
  3. Python recupera l'attributo "__new__" su S (l'equivalente di chiamare getattr(S, "__new__") in codice Python).
  4. Da S stata creata sulla classe CarModel, considera le classi seguenti CarModel nel MRO di CarModel, e trova "__new__" nel dict della classe object stessa. Il suo valore, un metodo statico, ha un metodo __get__, che viene chiamata con gli argomenti None e cls. Poiché __new__ è un metodo statico, il suo metodo __get__ restituisce semplicemente la funzione così com'è, non modificata. Pertanto, super(CarModel, cls).__new__ corrisponde esattamente a object.__new__.
  5. La funzione ottenuto nel passaggio precedente (cioè, object.__new__) viene richiamato con l'argomento cls, dove cls è probabilmente CarModel, infine una nuova istanza della classe CarModel.

spero che era affatto comprensibile.

(Per ragioni di completezza, si segnala che la funzione effettiva __new__ sulla classe object non è effettivamente un metodo statico, ma una speciale funzione incorporata che ha semplicemente alcun metodo __get__ affatto, ma poiché la Il metodo __get__ su metodi statici restituisce semplicemente la funzione con cui sono stati definiti, l'effetto è lo stesso.)

+0

In 'super (class1, class2)', in che modo 'super' usa' class1' e 'class2'? – Adrian

+0

@Adrian: Non credo di aver capito la tua domanda, perché suona come l'intera risposta è destinata a spiegare. C'è qualche parte particolare a riguardo? – Dolda2000

Problemi correlati