__new__ vs __init__
Gabriel Genellina
gagsl-py2 en yahoo.com.ar
Jue Nov 15 04:06:38 CET 2007
En Wed, 14 Nov 2007 12:19:44 -0300, Luis Rodrigo Gallardo Cruz
<rodrigo en nul-unu.com> escribió:
> On Wed, Nov 14, 2007 at 03:58:20PM +0100, tny wrote:
>> Sé que __new__ es llamado antes de que se cree el objeto, y es el
>> encargado de crearlo y devolverlo.
>>
>> Sé que __init__ es llamado después de __new__ para inicializarlo.
>
>> ¿Cuándo se debería emplear __init__ y cuando __new__?
>
> Usa __new__ cuando la creación del objeto no puede hacerse según las
> reglas normales de python. Por ejemplo, una forma (un poco fea en mi
> opinión) de implementar el patrón 'singleton' es que el __new__ de la
> clase, en vez de crear un objeto, regrese la instancia única.
>
> En general, usar __new__ es mágia. Casi siempre es mejor evitarlo.
Uh, porque? No hay nada de magia. Y no tiene que ver con que se salteen
las reglas normales o no.
La diferencia entre __new__ e __init__ es la que dice tny ahi arriba. Solo
que hay dos detalles importantes que faltan:
- si __new__ devuelve cualquier otra cosa que no es una instancia de la
clase pedida, el __init__ no se invoca
- los tipos inmutables (numeros, strings, tuplas...) *NO* invocan __init__
nunca, sino que la inicializacion se hace completamente dentro del __new__
(justamente porque son inmutables).
Asi que, por ejemplo, si uno quisiera heredar de tuple para representar un
punto del plano (x,y), la unica forma es usando __new__:
class Point2D(tuple):
"Un punto (x,y)"
def __new__(cls, *args):
if not args:
args = (0,0)
if len(args)!=2:
raise ValueError, "Point2D requiere dos argumentos: %s" %
repr(args)
return super(Point2D, cls).__new__(cls, args)
x = property(lambda self: self[0])
y = property(lambda self: self[1])
def __repr__(self):
return '%s(%r,%r)' % (type(self).__name__, self.x, self.y)
def __abs__(self):
from math import hypot
return hypot(self.x, self.y)
def __add__(self, other):
return type(self)(self.x+other.x, self.y+other.y)
py> P1 = Point2D(30, 40)
py> P2 = Point2D(5, 10)
py> P1+P2
Point2D(35,50)
py> abs(P1)
50.0
py> Point2D()
Point2D(0,0)
py> Point2D(1,2,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __new__
ValueError: Point2D requiere dos argumentos: (1, 2, 3)
--
Gabriel Genellina
------------ próxima parte ------------
_______________________________________________
Lista de correo Python-es
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes
Más información sobre la lista de distribución Python-es