web-dev-qa-db-fra.com

Comment utiliser correctement isinstance () de python pour vérifier si une variable est un nombre?

J'ai trouvé un vieux code Python qui faisait quelque chose comme:

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

Comme prévu, pep8 Se plaint de cette recommandation d'utilisation de isinstance().

Maintenant, le problème est que le module numbers a été ajouté dans Python 2.6 et j'ai besoin d'écrire du code qui fonctionne avec Python 2.5+

Donc if isinstance(var, Numbers.number) n'est pas une solution.

Quelle serait la bonne solution dans ce cas?

41
sorin

Dans Python 2, vous pouvez utiliser le module types :

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

Notez l'utilisation d'un Tuple pour tester contre plusieurs types.

Sous le capot, IntType n'est qu'un alias pour int, etc.:

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

Le type complex nécessite que votre python a été compilé avec la prise en charge des nombres complexes; si vous voulez protéger cela, utilisez un bloc 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)
...

ou si vous utilisez directement les types:

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

Dans Python 3 types n'a plus d'alias de type standard, complex est toujours activé et il n'y a plus de long vs int différence, donc dans Python 3 utilisez toujours:

NumberTypes = (int, float, complex)

Enfin, vous pouvez utiliser le type de base abstrait numbers.Numbers (nouveau dans Python 2.6) pour prendre également en charge les types numériques personnalisés qui ne le font pas dérivent directement des types ci-dessus:

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

Cette vérification renvoie également True pour les objets decimal.Decimal() et fractions.Fraction().

Ce module fait l'hypothèse que le type complex est activé; vous obtiendrez une erreur d'importation si ce n'est pas le cas.

101
Martijn Pieters

Python 2 prend en charge quatre types pour les nombres int, float, long et complexet python 3.x prend en charge 3: int, float et 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
18
Ashwini Chaudhary

Selon ce que vous utilisez dans typage du canard pourrait être une meilleure approche (c'est certainementcommunémentrecommandé ) . Le problème avec l'approche de Martijn Pieters est que vous manquerez toujours certains types de numéros de votre liste. Du haut de ma tête, votre code ne fonctionnera pas avec: les nombres rationnels sympy, les entiers de précision arbitraire et toute implémentation de nombres complexes.

Une alternative consiste à écrire une fonction comme celle-ci:

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

Ce code devrait fonctionner avec toute implémentation raisonnable d'un nombre. Bien sûr, il y a un inconvénient majeur: cela fonctionnera également avec une implémentation déraisonnable de nombreux non-nombres (c'est-à-dire si l'opérateur plus est surchargé et accepte un entier).

Une autre alternative (selon la raison pour laquelle vous devez savoir si quelque chose est un nombre) est de supposer simplement que c'est un nombre, et si ce n'est pas le cas, des erreurs seront lancées par le bit du code qui nécessite un nombre.

Je ne dis pas que ces approches sont toujours meilleures (contrairement à certaines personnes ...) juste qu'elles valent la peine d'être considérées.

3
dshepherd