2010-04-28 7 views
7

Quiero crear una subclase de un tipo numérico (digamos, int) en python y darle un constructor complejo brillante. Algo como esto:¿Cómo agregar un constructor a un tipo numérico subclasificado?

class NamedInteger(int): 
    def __init__(self, value): 
     super(NamedInteger, self).__init__(value) 
     self.name = 'pony' 

    def __str__(self): 
     return self.name 

x = NamedInteger(5) 
print x + 3 
print str(x) 

Esto funciona bien en Python 2.4, pero Python 2.6 muestra una advertencia de desaprobación. ¿Cuál es la mejor forma de subclasificar un tipo numérico y redefinir los constructores para los tipos integrados en las versiones más nuevas de Python?

Editar: visto en los comentarios que esto funciona sin una línea super(), por lo que podría ser así:

class NamedInteger(int): 
    def __init__(self, value): 
     self.name = 'pony' 

    def __str__(self): 
     return self.name 

x = NamedInteger(5) 
print x + 3 
print str(x) 

creo que esto funciona porque int es tipo inmutable y sólo tiene __new__ método. Sin embargo, me alegra saber de una manera correcta de subclases, por lo que podría construir una clase con el comportamiento de la siguiente manera:

x = NamedInteger(5, 'kitty') 

Segunda edición:

La versión final se verá así:

class NamedInteger(int): 
    def __new__(cls, value, name='pony'): 
     self = super(NamedInteger, cls).__new__(cls, value) 
     self.name = name 
     return self 

    def __str__(self): 
     return self.name 

x = NamedInteger(5) 
y = NamedInteger(3, 'kitty') 
print "%d %d" % (x, y) 
print "%s %s" % (x, y) 

Las respuestas a continuación también dieron enlaces muy interesantes a los módulos Abstract Base Classes y numbers.

+1

+1 Buena pregunta: consulte [este hilo en el rastreador de errores de Python] (http://bugs.python.org/issue1683368) para ver el historial de este cambio. – balpha

Respuesta

4

Tienes que usar __new__ en lugar de __init__ cuando subclases tipos incorporados inmutables, p. Ej.:

class NamedInteger(int): 

    def __new__(cls, value, name='pony'): 
     inst = super(NamedInteger, cls).__new__(cls, value) 
     inst.name = name 
     return inst 

    def __str__(self): 
     return self.name 

x = NamedInteger(5) 
print x + 3     # => 8 
print str(x)    # => pony 
x = NamedInteger(3, "foo") 
print x + 3     # => 6 
print str(x)    # => foo 
0

Se trabajará bien si usted no pasa valor a super(NamedInteger, self).__init__()

Me pregunto por qué sin embargo, estoy aprendiendo de tu post :-)

+0

Puse tu muestra de código en las comillas inversas para que se mostrara correctamente. Además, el problema con ese enfoque es que 'NamedInteger' no se inicializa con el valor adecuado. –

+0

¡Ah, tienes razón, y tienes un ojo de águila para detectar eso! Creo que ahora tengo una idea de por qué esto funciona sin super() – abbot

5

A partir de Python 2.6, la mejor forma de extender los tipos numéricos no deben heredar directamente de ellos, sino registrar su clase como una subclase de la clase base abstracta del número. Consulte the abc module para la documentación del concepto de la clase base abstracta.

La documentación de ese módulo enlaza con the numbers module, que contiene las clases base abstractas de las que puede declarar que forma parte. Así que, básicamente, diría

import numbers 
numbers.Number.register(NamedInteger) 

para indicar que su clase es un tipo de número.

Por supuesto, el problema con esto es que requiere implementar todos los diversos métodos de manejo como __add__, __mul__, etc. Sin embargo, realmente tendría que hacer esto de todos modos, ya que no puede confiar en la implementación de la clase int de esas operaciones para hacer lo correcto para su clase. Por ejemplo, ¿qué se supone que debe suceder cuando agrega un número entero a un número entero con nombre?

Según tengo entendido, el enfoque ABC pretende forzarte a enfrentar esas preguntas. En este caso, lo más simple es, probablemente, mantener un int como una variable de instancia de su clase; en otras palabras, si va a register su clase para otorgarle la relación is-a con Number, su implementación le da una relación has-a con int.

Cuestiones relacionadas