2012-06-26 11 views
32

Ho trovato un po 'di vecchio codice Python che stava facendo qualcosa di simile:Come usare correttamente isinstance() di python per verificare se una variabile è un numero?

if type(var) is type(1): 
    ... 

Come previsto, pep8 lamenta questo utilizzo raccomandando di isinstance().

Ora, il problema è che il modulo numbers è stata aggiunta in Python 2.6 e ho bisogno di scrivere codice che funziona con Python 2.5 +

Quindi if isinstance(var, Numbers.number) non è una soluzione.

Quale sarebbe la soluzione corretta in questo caso?

+0

Se si è disposti a usare numpy, 'numpy.isfinite' dovrebbe fare il trucco. –

risposta

83

È possibile utilizzare il types module:

>>> import types 
>>> var = 1 
>>> NumberTypes = (types.IntType, types.LongType, types.FloatType, types.ComplexType) 
>>> isinstance(var, NumberTypes) 
True 

Nota del uso di una tupla per testare contro più tipi.

Sotto il cofano, IntType è solo un alias per int, ecc .:

>>> isinstance(var, (int, long, float, complex)) 
True 

Il tipo complex necessario che il pitone è stato compilato con il supporto per i numeri complessi; se si vuole custodire per questo uso un blocco try/except:

>>> try: 
...  NumberTypes = (types.IntType, types.LongType, types.FloatType, types.ComplexType) 
... except AttributeError: 
...  # No support for complex numbers compiled 
...  NumberTypes = (types.IntType, types.LongType, types.FloatType) 
... 

o se semplicemente utilizzare i tipi direttamente:

>>> try: 
...  NumberTypes = (int, long, float, complex) 
... except NameError: 
...  # No support for complex numbers compiled 
...  NumberTypes = (int, long, float) 
... 

ultimo ma non meno importante, è possibile utilizzare il numbers.Numbers abstract base type (nuova in pitone 2.6) per supportare anche tipi numerici personalizzati che non derivano direttamente dai tipi di cui sopra:

>>> import numbers 
>>> isinstance(var, numbers.Number) 
True 

Questo modulo non fare l'ipotesi che il tipo complex è attivato; riceverai un errore di importazione se non lo è.

+3

'isinstance()' può prendere una tupla di oggetti?!? Woah, amico ... –

+0

@Def_Os: sì, e questa è stata una caratteristica da Python 2.2. –

+0

Dovresti davvero metterlo in cima alla tua risposta. –

13

Python 2 supporta quattro tipi per i numeri int, float, long e complex e python 3.x supporta 3: int, float e complex

>>> num = 10 
>>> if isinstance(num, (int, float, long, complex)): #use tuple if checking against multiple types 
     print('yes it is a number') 

yes it is a number 
>>> isinstance(num, float) 
False 
>>> isinstance(num, int) 
True 
>>> a = complex(1, 2) 
>>> isinstance(a, complex) 
True 
2

seconda di ciò che si sta utilizzando questo duck typing potrebbe essere un approccio migliore (è certainlycommonlyrecommended). Il problema con l'approccio di Martijn Pieters è che ti mancheranno sempre alcuni tipi di numeri dalla tua lista. In cima alla mia testa il tuo codice non funzionerà: numeri razionali sympy, interi di precisione arbitrari e qualsiasi implementazione di numeri complessi.

Un'alternativa è scrivere una funzione come questa:

def is_number(thing): 
    try: 
     thing + 1 
     return True 
    except TypeError: 
     return False 

Questo codice dovrebbe funzionare con qualsiasi ragionevole attuazione di un numero. Naturalmente c'è uno svantaggio importante: funzionerà anche con un'implementazione irragionevole di molti numeri diversi (ad esempio se l'operatore più è sovraccarico e accetta un numero intero).

Un'altra alternativa (a seconda del motivo per cui è necessario sapere se qualcosa è un numero) è solo supporre che sia un numero, e se non è un errore verrà generato da qualsiasi bit del codice richiede un numero.

Non sto dicendo che questi approcci sono sempre migliori (a differenza di alcune persone ...) solo che valgono la pena considerarli.

Problemi correlati