2009-12-20 8 views
9

Su Python 2.5 Ho bisogno di usare numeri float con un metodo modificato __str__(). Inoltre ho bisogno di sapere quando il costruttore fallisce.Sottoclasse di tipo float in Python, non riesce a rilevare l'eccezione in __init __()

Perché non riesco a rilevare le eccezioni sollevate da float.__init__()?

Qual è il modo migliore per consultare il valore numerico del mio oggetto float derivato? Nel mio codice sto 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 

risposta

17

float è immutabile, pertanto il suo __init__, l'iniziatore , è fondamentalmente un no-op - non può accadere nulla di sostanziale, essere l'oggetto self non può essere modificato (se in realtà è un'istanza di float anziché di una sottoclasse, ma ovviamente lo float dello stesso __init__ deve operare su tale presupposto ;-).

Pertanto, tutta l'azione avviene in __new__, costruttore adeguata, come per altri tipi immutabili come int, str, tuple, e così via. È un errore comune credere che __init__ sia un costruttore: non lo è, prende un oggetto già costruito come primo argomento, self, e lo "inizializza" (se possibile, cioè, se quello self è modificabile! -) - la costruzione dello stesso avviene nello __new__.

Così, il vostro float sottoclasse dovrebbe iniziare:

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

e si può rimuovere la __init__, che non è necessario. Ora:

>>> 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 

(naturalmente, che avrebbe funzionato ancora meglio se si fatto avere una classe My_Error un'eccezione definita ;-).

+0

Funziona !, grazie per la spiegazione. – Ricardo

7

provare __new__ invece:

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") 

anche "auto" è un galleggiante già così non c'è bisogno di dire galleggiante (auto), proprio "sé" farà:

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

Grazie !, ha funzionato perfettamente. Informazioni su ""% .2f "% self", quale metodo viene utilizzato per la conversione della stringa? 'Galleggiare .__ str __()'? Ho pensato che fosse 'F .__ str __()' che non lo è, perché non esiste una ricorsione infinita. – Ricardo

Problemi correlati