2012-01-29 26 views
6

Nota: Parte de una implementación de peso mosca con Pythonlo que hace `super()` `en __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 

Pregunta 1> ¿qué significa super()? ¿Significa la clase principal de CarModel?

Pregunta 2> También tengo dificultades para entender cómo funciona la función __new__? Específicamente, la siguiente línea.

model = super().__new__(cls) 

Descripción de __new__:

La función se llama al constructor __new__ en contraposición a __init__ y acepta exactamente un argumento, la clase que se está construyendo (que se llama antes de que el objeto es construido, por lo que no hay auto argumento ). También tiene que devolver el objeto recién creado.

+1

@Ben, basado en el [documento] (http://docs.python.org/py3k/reference/datamodel.html # objects-values-and-types), '__new __()' devuelve una instancia de 'cls'. ¿por qué el código 'modelo = super() .__ nuevo __ (cls) ' en OP puede crear una instancia de 'cls'? ¿Cómo sabe la súper clase de CarModel cómo crear una instancia de su subclase? – q0987

+2

Esa sería una gran pregunta SO por sí misma (si aún no se ha hecho). La respuesta corta es que le está pasando la clase actual con el parámetro 'cls'. En última instancia, no hay forma de crear realmente una instancia nueva sin retrasar todo el camino de regreso a 'object .__ new__', porque Python no tiene instrucciones para" asignar una instancia ". Pero 'object .__ new__' sabe crear una instancia de la clase que ha pasado (que también será una instancia de' object', porque todo es una instancia de 'object'). – Ben

Respuesta

1

super() se utiliza para hacer referencia a la superclase (es decir, la clase primaria de la que está creando una subclase).

__new__ es un método que se invoca para crear una nueva instancia de la clase, si está definida.

+0

En 'super (class1, class2)', ¿cómo 'super' utiliza' class1' y 'class2'? – Adrian

1

Creo que está utilizando Python3, donde no es necesario que el súper tenga el mismo nombre de clase. Súper se refiere a las clases base de la clase actual y hace el correcto Method Resolution Order para que invoque el método de la clase base correcta. __new__ es el método que se invoca para crear una instancia. Es el first step in the instance creation.

+0

En 'super (class1, class2)', ¿cómo 'super' utiliza' class1' y 'class2'? – Adrian

11

Para comenzar con super() en sí mismo es simplemente la abreviatura de super(A, B), donde A es la clase en la que se produce el código, y B es el primer argumento de la función en la que se produce el código; entonces en su caso particular, super().__new__(cls) se expande a super(CarModel, cls).__new__(cls).

A su vez, super(T, O) devuelve un "súper objeto". Para comprender lo que hace un súper objeto, necesita comprender cómo funcionan las referencias de atributos en instancias y clases en Python.

suponiendo que no hay __getattr__ o __getattribute__ métodos están involucrados, haciendo referencia a atributo A sobre un objeto O (es decir, la evaluación de O.A o getattr(O, "A")) procede a través de los siguientes pasos:

  1. Si "A" se define en la instancia O 's dict (O.__dict__), entonces el valor en ese dict se devuelve directamente, precisamente como es.
  2. De lo contrario, cada una de las clases en el orden de resolución de método O se comprueban sucesivamente, buscando "A" en cada uno de sus dictados. Si se encuentra, llame al valor D.
  3. Si D, a su vez, no define un __get__, entonces se devuelve tal como está.Si lo hace, sin embargo, entonces D se conoce como un "descriptor", y se llama a su método __get__ con O como primer argumento, y type(O) como el segundo argumento.

Una referencia atributo en una clase de trabajos sobre el mismo, la sustitución de la clase siendo referencia para el ejemplo, con las siguientes diferencias:

  • Paso 1 no se aplica.
  • Se llama al método __get__ con None como primer argumento, y la clase a la que se hace referencia como segunda.

Python utiliza descriptores para implementar cosas tales como métodos de instancia, métodos de clase, métodos estáticos y propiedades.

Un objeto súper creada con super(T, O), entonces, es un objeto (built-in) con un método __getattribute__ que se llama en cada atributo de referencia en él, y busca el atributo en los dicts de los sólo las clases siguientes T en O MRO. El valor que encuentra, llama al __get__ como de costumbre.

El proceso es un poco complejo, por ejemplo, así es como funcionaría en su caso específico. Como CarModel se define tal como es, su MRO es [CarModel, object].

  1. super().__new__(cls) se expande a super(CarModel, cls).__new__(cls), como se describió anteriormente.
  2. super(CarModel, cls) se evalúa para generar un superobjeto S.
  3. Python obtiene el atributo "__new__" en S (el equivalente a llamar a getattr(S, "__new__") en código Python).
  4. Desde S fue creado en la clase CarModel, considera las siguientes clases CarModel en el MRO de CarModel, y encuentra "__new__" en el dict de la clase object sí. Su valor, un método estático, tiene un método __get__, que se llama con los argumentos None y cls. Como __new__ es un método estático, su método __get__ simplemente devuelve la función tal como está, sin modificaciones. Por lo tanto, super(CarModel, cls).__new__ es exactamente lo mismo que object.__new__.
  5. La función obtenida en el paso anterior (es decir, object.__new__) se llama con el argumento cls, donde cls es probablemente CarModel, por último, una nueva instancia de la clase CarModel.

Espero que sea del todo comprensible.

(Para mayor abundamiento, cabe mencionar que el __new__ función real de la clase object no es en realidad un método estático, sino una función incorporada en especial que simplemente no tiene un método __get__ en absoluto, pero dado que el __get__ método en métodos estáticos simplemente devuelve la función con la que se definieron, el efecto es el mismo.)

+0

En 'super (class1, class2)', ¿cómo 'super' utiliza' class1' y 'class2'? – Adrian

+0

@Adrian: No creo entender su pregunta, porque eso suena como lo que toda la respuesta debe explicar. ¿Hay alguna parte en particular al respecto? – Dolda2000

Cuestiones relacionadas