__new__ __init__ python constructor new-operator metaclass init

python - ¿Hay alguna razón para elegir__new__ over__init__ cuando se define una metaclase?



metaclass python (4)

Siempre configuré metaclases algo como esto:

class SomeMetaClass(type): def __new__(cls, name, bases, dict): #do stuff here

Pero me encontré con una metaclase que se definió así:

class SomeMetaClass(type): def __init__(self, name, bases, dict): #do stuff here

¿Hay alguna razón para preferir uno sobre el otro?

Actualización : tenga en cuenta que estoy preguntando sobre el uso de __new__ y __init__ en una metaclase. Ya entiendo la diferencia entre ellos en otra clase. Pero en una metaclase, no puedo usar __new__ para implementar el almacenamiento en caché porque __new__ solo se llama a la creación de clases en una metaclase.


Como se ha dicho, si tiene la intención de alterar algo como las clases base o los atributos, tendrá que hacerlo en __new__ . Lo mismo es cierto para el name de la clase, pero parece haber una peculiaridad con él. Cuando cambias el name , no se propaga a __init__ , aunque, por ejemplo, attr es.

Entonces tendrás:

class Meta(type): def __new__(cls, name, bases, attr): name = "A_class_named_" + name return type.__new__(cls, name, bases, attr) def __init__(cls, name, bases, attr): print "I am still called ''" + name + "'' in init" return super(Meta, cls).__init__(name, bases, attr) class A(object): __metaclass__ = Meta print "Now I''m", A.__name__

huellas dactilares

I am still called ''A'' in init Now I''m A_class_named_A

Esto es importante de saber, si __init__ llama a una súper metaclase que hace algo de magia adicional. En ese caso, uno tiene que cambiar el nombre de nuevo antes de llamar a super.__init__ .


Puede implementar el almacenamiento en caché. Person("Jack") siempre devuelve un nuevo objeto en el segundo ejemplo, mientras que puede buscar una instancia existente en el primer ejemplo con __new__ (o no devolver nada si lo desea).


Puede ver la descripción completa en los documentos oficiales , pero básicamente se llama a __new__ antes de que se __new__ el nuevo objeto (con el fin de crearlo) y se __init__ después de que se crea el nuevo objeto (con el fin de inicializarlo).

Usar __new__ permite trucos como el almacenamiento en memoria caché de objetos (siempre devolviendo el mismo objeto para los mismos argumentos en lugar de crear nuevos) o produciendo objetos de una clase diferente a la solicitada (a veces utilizada para devolver subclases más específicas de la clase solicitada). En general, a menos que esté haciendo algo bastante extraño, __new__ tiene una utilidad limitada. Si no necesita invocar dicho engaño, __init__ con __init__ .


Si quiere alterar los atributos dict antes de que se cree la clase, o cambie las bases de la tupla, tiene que usar __new__ . Para cuando __init__ ve los argumentos, el objeto de clase ya existe. Además, debe usar __new__ si desea devolver algo que no sea una clase recién creada del tipo en cuestión.

Por otro lado, para el momento en que __init__ ejecuta, la clase existe. Por lo tanto, puede hacer cosas como dar una referencia a la clase recién creada a uno de sus objetos miembros.

Editar : cambió la redacción para dejar más claro que por "objeto", me refiero a objeto de clase.