web-dev-qa-db-ja.com

Pythonで変数を型チェックするにはどうすればよいですか?

私はPython関数が数値引数を取ります必須が正しく動作するためには整数でなければなりません)を持っています。Pythonでこれを確認するための推奨される方法は何ですか?

私の最初の反応はこのようなことをすることです:

def isInteger(n):
    return int(n) == n

しかし、私はこれが1)高価である、2)醜い、そして3)マシンイプシロンの優しい慈悲の対象であると考えざるを得ません。

Pythonは、型チェック変数のネイティブな手段を提供しますか?それとも、これは言語の動的に型付けされた設計の違反と見なされますか?

編集:多くの人が尋ねてきたので-問題のアプリケーションはIPv4プレフィックスで動作し、フラットテキストファイルからデータを調達します。入力がフロートに解析される場合、そのレコードは不正な形式と見なされ、無視されます。

32
Murali Suriar
_isinstance(n, int)
_

それが間違いなく実際のintであり、intのサブクラスではないかどうかを知る必要がある場合(通常、これを行う必要はありません):

_type(n) is int
_

この:

_return int(n) == n
_

クロスタイプの比較が真になる可能性があるため、これはそれほど良い考えではありません-特にint(3.0)==3.0

33
bobince

ええ、エヴァンが言ったように、チェックをタイプしないでください。値を使用してみてください:

_def myintfunction(value):
   """ Please pass an integer """
   return 2 + value
_

タイプチェックはありません。それははるかに優れています!やってみるとどうなるか見てみましょう:

_>>> myintfunction(5)
7
_

これは整数なので、機能します。うーん。テキストを試してみましょう。

_>>> myintfunction('text')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myintfunction
TypeError: unsupported operand type(s) for +: 'int' and 'str'
_

とにかく何をすべきかというエラーTypeErrorが表示されます。呼び出し側がそれをキャッチしたい場合、それは可能です。

タイプチェックを行ったらどうしますか?エラーを表示しますか?そのため、エラーはすでに自動的に表示されているため、タイプチェックを行う必要はありません。

さらに、型チェックを行わなかったため、関数は他の型で機能します。

フロート:

_>>> print myintfunction(2.2)
4.2
_

複素数:

_>>> print myintfunction(5j)
(2+5j)
_

小数:

_>>> import decimal
>>> myintfunction(decimal.Decimal('15'))
Decimal("17")
_

数字を追加できる完全に任意のオブジェクトでさえ!

_>>> class MyAdderClass(object):
...     def __radd__(self, value):
...             print 'got some value: ', value
...             return 25
... 
>>> m = MyAdderClass()
>>> print myintfunction(m)
got some value:  2
25
_

したがって、型チェックを行っても何も得られません。そして、多くを失います。


更新:

質問を編集したので、アプリケーションがintでのみ意味のある上流ルーチンを呼び出すことは明らかです。

その場合でも、パラメーター受け取ったとおりを上流の関数に渡す必要があります。アップストリーム関数はそれを正しく処理します。必要に応じてエラーを発生させます。私は非常に疑わしい IPを処理する関数に、floatを渡すと奇妙な動作をします。ライブラリの名前を教えていただければ、確認させていただきます。

しかし...上流の関数が正しく動作せず、浮動小数点数を渡した場合に一部の子供を殺す場合(私はまだ疑っています)、単にint()を呼び出すだけです。

_def myintfunction(value):
   """ Please pass an integer """
   return upstreamfunction(int(value))
_

あなたはまだタイプチェックをしていないので、タイプチェックをしないことのほとんどの利点を得ます。


それでも、アプリケーションの可読性とパフォーマンスを低下させてもまったく効果がないにもかかわらず、本当にチェックを入力したい場合は、assertを使用してください。

_assert isinstance(...)
assert type() is xxxx
_

そうすれば、assertsをオフにして、この_<sarcasm>_feature_</sarcasm>_を呼び出すことにより、プログラムから削除できますなので

_python -OO program.py
_
16
nosklo
if type(n) is int

これは、nがPython int、およびonly intであるかどうかをチェックします。intのサブクラスは受け入れません。

ただし、型チェックは「Pythonの方法」には適合しません。 nをintとして使用することをお勧めします。それが例外をスローする場合は、それをキャッチして処理します。

4
Nikhil Chelliah

Pythonは typing module および mypy を介して 段階的なタイピング をサポートするようになりました。 typingモジュールは、Python 3.5)の時点でstdlibの一部であり、ダウンロードできます PyPiから Python 2または以前のバージョンのPython 3. 3.コマンドラインからpip install mypyを実行して、mypyをインストールできます。

つまり、一部の関数がint、floatを受け取り、文字列を返すことを確認するには、次のように関数に注釈を付けます。

def foo(param1: int, param2: float) -> str:
    return "testing {0} {1}".format(param1, param2)

ファイルの名前がtest.pyの場合、mypyをインストールしたら、コマンドラインからmypy test.pyを実行してタイプチェックできます。

古いバージョンのPythonを関数アノテーションのサポートなしで使用している場合は、型コメントを使用して同じ効果を実現できます。

def foo(param1, param2):
    # type: (int, float) -> str
    return "testing {0} {1}".format(param1, param2)

Python 3ファイルの場合は同じコマンドmypy test.pyを使用し、Python 2ファイルの場合はmypy --py2 test.pyを使用します。

型アノテーションは、実行時にPythonインタープリターによって完全に無視されるため、オーバーヘッドが最小限またはまったく発生しません。通常のワークフローは、コードで作業し、mypyを定期的に実行してミスやエラーをキャッチすることです。 PyCharmなどの一部のIDEは、型のヒントを理解し、直接編集しているときにコードの問題や型の不一致を警告できます。

なんらかの理由で、実行時に型をチェックする必要がある場合(おそらく、多くの入力を検証する必要がある場合)、他の回答にリストされているアドバイスに従う必要があります。 isinstanceissubclassなどを使用します。 enforce のようないくつかのライブラリーもあり、実行時にタイプチェック(タイプアノテーションを尊重する)を実行しようとしますが、執筆時点ではそれらがどのようにプロダクションに対応できるかは不明です。

詳細と詳細については、 mypy Webサイトmypy FAQ 、および PEP 484 を参照してください。

4
Michael0x2a

Pythonでプログラミングし、他の言語のようにタイプチェックを実行することは、釘を打ち込むためにドライバーを選択することのようです。Pythonの例外処理機能を使用する方がよりエレガントです。

対話型のコマンドラインから、次のようなステートメントを実行できます。

int('sometext')

それはエラーを生成します-ipythonは私に言っています:

<type 'exceptions.ValueError'>: invalid literal for int() with base 10: 'sometext'

これで、次のようなコードを記述できます。

try:
   int(myvar) + 50
except ValueError:
   print "Not a number"

これをカスタマイズして、必要な操作を実行し、予想されるエラーをキャッチできます。少し複雑に見えますが、Python)の構文とイディオムに適合し、非常に読みやすいコードになります(Pythonを話すのに慣れると)。

1
basswulf

チェックを入力しないでください。アヒルのタイピングの要点は、あなたがする必要はないということです。たとえば、誰かが次のようなことをしたらどうなるでしょう:

class MyInt(int):
    # ... extra stuff ...
1
Evan Fosmark

どのように:

def ip(string):
    subs = string.split('.')
    if len(subs) != 4:
        raise ValueError("incorrect input")
    out = Tuple(int(v) for v in subs if 0 <= int(v) <= 255)
    if len(out) != 4:
        raise ValueError("incorrect input")
    return out

もちろん、標準のisinstance(3、int)関数があります...

0
Lars

私は次のようなものに誘惑されます:

def check_and_convert(x):
    x = int(x)
    assert 0 <= x <= 255, "must be between 0 and 255 (inclusive)"
    return x

class IPv4(object):
    """IPv4 CIDR prefixes is A.B.C.D/E where A-D are 
       integers in the range 0-255, and E is an int 
       in the range 0-32."""

    def __init__(self, a, b, c, d, e=0):
        self.a = check_and_convert(a)
        self.b = check_and_convert(a)
        self.c = check_and_convert(a)
        self.d = check_and_convert(a)
        assert 0 <= x <= 32, "must be between 0 and 32 (inclusive)"
        self.e = int(e)

そうすれば、それを使用しているときに何でも渡すことができますが、有効な整数のみを格納できます。

0
James Brooks