¿Alguna idea sobre el mejor trabajo alrededor para __nuevo__ perder sus argumentos?

Entonces, solo me di cuenta hoy de que __new__ está en desuso por recibir argumentos, a partir de python 2.6 (no se menciona en la documentación, lo que tampoco es cierto en términos del comportamiento de __new__ llama a __init__ por lo que puedo ver). Esto significa que mi código funcional ha comenzado a generar advertencias y quiero deshacerme de ellas. Pero no puedo ver una forma elegante de trabajar alrededor.

Tengo un montón de clases que realizan optimizaciones cuando se construyen. Así que tengo

 class Conjunction(Base): def __new__(cls, a, b): if a == True: return b elif b == True return a else: return super(Conjunction,cls).__new__(cls, a, b) 

Y así sucesivamente (las versiones reales cubren muchos más casos). Entonces, a diferencia de lo que dice Guido en esta respuesta (la única referencia que puedo encontrar), mi método __new__ usa sus argumentos, y no puede ser reemplazado por una función __init__ anulada.

Lo mejor que puedo hacer es dividir esto en dos:

 def Conjunction(a, b): if a == True: return b elif b == True return a else: return ConjunctionImpl(a, b) class ConjunctionImpl(Base): # ... 

Pero eso es simplemente feo y apesta al cielo alto. ¿Me estoy perdiendo una forma elegante de que un constructor de clase devuelva algún objeto arbitrario en función de los parámetros del constructor que se proporciona?

__new__ no está “en desuso para recibir argumentos”. Lo que cambió en Python 2.6 es que el object.__new__ , el método __new__ de la clase de objeto , ya no ignora ningún argumento que haya pasado. (el object.__init__ tampoco ignora más los argumentos, pero eso es solo una advertencia en 2.6.) No puede usar el object como la clase de terminación para su herencia si desea pasar argumentos a __new__ o __init__ .

Para que cualquier código dependa de que el comportamiento funcione en 2.6, solo tiene que reemplazar el object como la clase base, utilizando una clase base que acepte adecuadamente los argumentos adicionales y no los transfiera en las llamadas que realiza (usando super() .)

Thomas me puso en la respuesta correcta, pero debo agregar que la solución en mi caso fue trivial: agregue un método __new__ a mi clase base con las líneas:

 class Base(object): def __new__(cls, *args, **kws): instance = super(Base, cls).__new__(cls) instance.__init__(*args, **kws) return instance 

Bueno, esto me dio curiosidad porque no vi la desaprobación en la documentación, así que lo intenté yo mismo.

 class Foo(object): def __new__(cls, a, b): if a: return a elif b: return b else: return super(Foo, cls).__new__(cls, a, b) def __init__(self, a, b): self.a = a self.b = b class Bar(Foo): def __new__(cls, x, y): if x: return x if y: return y else: return super(Bar, cls).__new__(cls, x, y) foo = Bar(False, False) 

Como se puede ver en este ejemplo, anulé la inicialización en Foo porque cualquier argumento pasado a nuevo se reenviará a la instancia de cls que __new__ intenta crear. La instancia de foo con ser de una clase de Bar, pero tendrá miembros a y b. Hice que se __init__ al __init__ la súper clase sin __init__ . El método __new__ siempre pasa sus __init__ a __init__ . Si no reemplaza el objeto __init__ para el objeto, se producirá un error ya que el método no __init__ .

Esa es mi opinión sobre el uso de lo nuevo en Python 2.7. Según los documentos 2.6 es similar.