2009-12-20 7 views
9

En Python 2.5 Necesito usar números flotantes con un método __str__() modificado. También necesito saber cuándo falla el constructor.Subclasificación de tipo flotante en Python, falla al detectar excepciones en __init __()

¿Por qué no puedo detectar las excepciones planteadas en float.__init__()?

¿Cuál es la mejor manera de consultar el valor numérico de mi objeto flotante derivado? En mi código estoy usando float(self).

class My_Number(float): 
    def __init__(self, float_string): 
     try: 
      super(My_Number, self).__init__(float_string) 
     except (TypeError, ValueError): 
      raise My_Error(float_string) 

    def __str__(self): 
     if int(float(self)) == float(self): 
      return str(int(float(self))) 
     else: 
      return str(round(float(self), 2)) 


>>> n = My_Number('0.54353') 
>>> print n 
0.54 

>>> n = My_Number('5.0') 
>>> print n 
5 

>>> n = My_Number('foo') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: invalid literal for float(): foo 

Respuesta

17

float es inmutable, por lo tanto, es __init__, el inicializador , es básicamente un no-operativo - nada sustancial puede suceder allí, sea porque el objeto self no se puede modificar (si en realidad es una instancia de float en lugar de una subclase, pero por supuesto float tiene debe funcionar bajo esa suposición ;-).

Por lo tanto, toda la acción sucede en __new__, el constructor adecuada, al igual que para otros tipos inmutables como int, str, tuple, y así sucesivamente. Es un error común creer que __init__ es un constructor: no lo es, toma un objeto ya construido como su primer argumento, self, y lo "inicializa" (si es factible, es decir, si ese self es mutable! -) - la construcción sucede en __new__.

lo tanto, su float subclase debe comenzar:

class My_Number(float): 
    def __new__(cls, float_string): 
    try: return float.__new__(cls, float_string) 
    except (TypeError, ValueError): raise My_Error(float_string) 

y se puede quitar el __init__, lo que no se necesita. Ahora:

>>> n = My_Number('foo') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in __new__ 
NameError: global name 'My_Error' is not defined 

(por supuesto, que funcionaría mejor si hizo tener una clase My_Error excepción definida ;-).

+0

¡Trabaja !, gracias por la explicación. – Ricardo

7

tratar __new__ lugar:

class F(float): 
    def __new__(cls, *arg, **kw): 
     try: 
      return float.__new__(cls, *arg, **kw) 
     except ValueError: 
      raise Exception("foo") 

print F("3.5")    
print F("asdf") 

también "auto" es un flotador ya que no hay necesidad de decir flotador (auto), simplemente "sí" va a hacer:

def __str__(self): 
    return "%.2f" % self 
+0

¡Gracias !, funcionó a la perfección. Acerca del '"% .2f "% self', ¿qué método se utiliza para la conversión de cadenas? 'flotar .__ str __()'? Pensé que era 'F .__ str __()' que no lo es, porque no hay recursión infinita. – Ricardo

Cuestiones relacionadas