Python >> Tutoriel Python >  >> Python

Quelle est la manière la plus pythonique de vérifier si un objet est un nombre ?

Utilisez Number du numbers module pour tester isinstance(n, Number) (disponible depuis la 2.6).

>>> from numbers import Number
... from decimal import Decimal
... from fractions import Fraction
... for n in [2, 2.0, Decimal('2.0'), complex(2, 0), Fraction(2, 1), '2']:
...     print(f'{n!r:>14} {isinstance(n, Number)}')
              2 True
            2.0 True
 Decimal('2.0') True
         (2+0j) True
 Fraction(2, 1) True
            '2' False

Ceci est, bien sûr, contraire au typage canard. Si vous êtes plus préoccupé par la façon dont un objet agit plutôt que ce qu'il est , effectuez vos opérations comme si vous aviez un nombre et utilisez des exceptions pour vous indiquer le contraire.


Vous voulez vérifier si un objet

agit comme un numéro dans certaines circonstances

Si vous utilisez Python 2.5 ou une version antérieure, le seul véritable moyen est de vérifier certaines de ces "certaines circonstances" et de voir.

En 2.6 ou supérieur, vous pouvez utiliser isinstance avec numbers.Number -- une classe de base abstraite (ABC) qui existe exactement dans ce but (beaucoup plus d'ABC existent dans le collections module pour diverses formes de collections/conteneurs, toujours à partir de 2.6 ; et, uniquement dans ces versions, vous pouvez facilement ajouter vos propres classes de base abstraites si vous en avez besoin).

Bach à 2.5 et versions antérieures,"peut être ajouté à 0 et n'est pas itérable" pourrait être une bonne définition dans certains cas. Mais, vous devez vraiment vous demander, ce que vous demandez que ce que vous voulez considérer comme "un nombre" doit certainement pouvoir faire , et ce qu'il doit absolument être incapable faire -- et vérifier.

Cela peut également être nécessaire dans la version 2.6 ou ultérieure, peut-être dans le but de faire vos propres enregistrements pour ajouter des types qui vous intéressent et qui n'ont pas encore été enregistrés sur numbers.Numbers -- si vous souhaitez exclure certains types qui prétendent qu'ils sont des nombres mais que vous ne pouvez tout simplement pas gérer, cela prend encore plus de soin, car les ABC n'ont pas de unregister méthode [[par exemple, vous pouvez créer votre propre ABC WeirdNum et enregistrez-y tous ces types étranges pour vous, puis vérifiez d'abord isinstance celui-ci pour renflouer avant de procéder à la vérification de isinstance du numbers.Number normal pour continuer avec succès.

BTW, si et quand vous devez vérifier si x peut ou ne peut pas faire quelque chose, vous devez généralement essayer quelque chose comme :

try: 0 + x
except TypeError: canadd=False
else: canadd=True

La présence de __add__ en soi ne vous dit rien d'utile, puisque par exemple toutes les séquences l'ont dans le but de concaténation avec d'autres séquences. Cette vérification équivaut à la définition "un nombre est quelque chose tel qu'une séquence de telles choses est un argument unique valide pour la fonction intégrée sum ", par exemple. Des types totalement bizarres (par exemple, ceux qui déclenchent la "mauvaise" exception lorsqu'ils sont additionnés à 0, comme, par exemple, un ZeroDivisionError ou ValueError &c) propagera une exception, mais ce n'est pas grave, faites savoir à l'utilisateur dès que possible que de tels types fous ne sont tout simplement pas acceptables en bonne compagnie ;-); mais, un "vecteur" qui peut être sommé à un scalaire (la bibliothèque standard de Python n'en a pas, mais bien sûr, ils sont populaires en tant qu'extensions tierces) donnerait également le mauvais résultat ici, donc (par exemple) cette vérification devrait venir après celui "non autorisé à être itérable" (par exemple, vérifiez que iter(x) augmente TypeError , ou pour la présence de la méthode spéciale __iter__ -- si vous êtes en version 2.5 ou antérieure et que vous avez donc besoin de vos propres vérifications).

Un bref aperçu de ces complications peut suffire à vous motiver à vous fier plutôt à des classes de base abstraites chaque fois que cela est possible...;-).


C'est un bon exemple où les exceptions brillent vraiment. Faites simplement ce que vous feriez avec les types numériques et attrapez le TypeError de tout le reste.

Mais évidemment, cela ne vérifie que si une opération fonctionne , pas si cela a du sens ! La seule vraie solution pour cela est de ne jamais mélanger les types et de toujours savoir exactement à quelle classe de types appartiennent vos valeurs.