web-dev-qa-db-ja.com

pythonのisinstance()を適切に使用して、変数が数値であるかどうかを確認する方法は?

私はいくつかの古いPythonのようなことをしているコードを見つけました:

_if type(var) is type(1):
   ...
_

予想どおり、_pep8_はisinstance()の使用を推奨していることについて不満を言っています。

今、問題はnumbersモジュールがPython 2.6で追加され、Python 2.5+

したがって、if isinstance(var, Numbers.number)は解決策ではありません。

この場合、適切な解決策はどれですか?

41
sorin

Python 2では、 typesモジュール を使用できます。

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

Tupleを使用して複数のタイプに対してテストすることに注意してください。

内部では、IntTypeintなどの単なるエイリアスです。

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

complexタイプでは、pythonが複素数をサポートするようにコンパイルされている必要があります。これを防ぐには、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)
...
_

または、タイプを直接使用する場合:

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

Python 3 typesは標準タイプのエイリアスを持たなくなり、complexは常に有効になり、long vs int差なので、Python 3では常に以下を使用します:

_NumberTypes = (int, float, complex)
_

最後になりましたが、 _numbers.Numbers_ abstract base type (Python 2.6)の新機能)を使用して、派生しないカスタム数値型もサポートできます上記のタイプから直接:

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

このチェックは、decimal.Decimal()およびfractions.Fraction()オブジェクトのTrueも返します。

このモジュールは、complexタイプが有効になっていると仮定しています。そうでない場合、インポートエラーが発生します。

101
Martijn Pieters

Python 2は、数値intfloatlongおよびcomplexand python 3.xは3:intfloatおよび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

ダックタイピング でこれを使用しているものに応じて、より良いアプローチになる可能性があります( 確かに一般的に推奨 ) 。 Martijn Pietersのアプローチの問題点は、リストからいくつかのタイプの数値が常に欠落することです。私の頭の上では、あなたのコードは動作しません:sympy有理数、任意精度の整数、複素数の実装。

1つの選択肢は、次のような関数を記述することです。

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

このコードは、数値の合理的な実装で機能するはずです。もちろん、大きな欠点もあります:それはまた、多くの非数値の不合理な実装でも動作します(つまり、プラス演算子がオーバーロードされて整数を受け入れる場合)。

別の選択肢(何かが数字であるかどうかを知る必要性に応じて)は、それが数字であると仮定することです。そうでない場合は、コードのどのビットでも数字が必要なエラーがスローされます。

これらのアプローチが(一部の人々とは異なり)常に優れているとは言っていません。

3
dshepherd