40

正しく動作するために整数でなければならない数値引数を取る Python 関数があります。Python でこれを確認する好ましい方法は何ですか?

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

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

しかし、これは 1) 高価である、2) 醜い、3) マシン イプシロンの優しい慈悲の対象であると思わずにはいられません。

Does Python provide any native means of type checking variables? Or is this considered to be a violation of the language's dynamically typed design?

EDIT: since a number of people have asked - the application in question works with IPv4 prefixes, sourcing data from flat text files. If any input is parsed into a float, that record should be viewed as malformed and ignored.

4

9 に答える 9

49
isinstance(n, int)

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

type(n) is int

これ:

return int(n) == n

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

于 2009-01-21T00:06:11.430 に答える
15

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

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 でのみ意味のあるアップストリーム ルーチンを呼び出していることは明らかです。

その場合は、受信したパラメーターを上流の関数に渡す必要があると思います。アップストリーム関数は、必要に応じてエラーを発生させるなど、正しく処理します。floatを渡すと、IP を処理する関数が奇妙に動作することはないと思います図書館の名前を教えていただければ、それを確認できます。

しかし...アップストリーム関数が正しく動作せず、floatを渡すと一部の子供が殺される場合(私はまだそれを非常に疑っています)、それを呼び出すだけですint()

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

あなたはまだ型チェックをしていないので、型チェックをしないことのほとんどの利点を得ることができます。


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

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

そうすれば、 s をオフにして、この機能を次のように呼び出すことでプログラムからassert削除できます。<sarcasm></sarcasm>

python -OO program.py
于 2009-01-21T02:50:17.217 に答える
5

Python は、 typing モジュールmypyを介した段階的な型付けをサポートするようになりました。このモジュールは、Python 3.5 の stdlib の一部であり、Python 2 または Python 3 の以前のバージョンのバックポートが必要な場合は、PyPi からダウンロードできます。コマンド ラインから実行してインストールできます。typingmypypip install 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)

mypy test.pyPython 3 ファイルとPython 2 ファイルに同じコマンドを使用しmypy --py2 test.pyます。

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

何らかの理由で、実行時に型をチェックする必要がある場合 (おそらく、多くの入力を検証する必要がありますか?)、他の回答に記載されているアドバイスに従う必要があります。たとえばisinstanceissubclass、 などを使用します。実行時に型チェック (型注釈を尊重) を実行しようとする強制などのライブラリもありますが、執筆時点でそれらがどの程度本番環境に対応しているかは不明です。

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

于 2016-06-29T07:00:10.663 に答える
4
if type(n) is int

これnは Python の intか、intだけかをチェックします。のサブクラスは受け入れませんint

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

于 2009-01-21T00:08:19.383 に答える
1

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を話すことに慣れたら)。

于 2009-03-25T16:34:53.117 に答える
1

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

class MyInt(int):
    # ... extra stuff ...
于 2009-01-21T01:32:11.350 に答える
0

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

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)

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

于 2009-11-24T11:14:35.247 に答える