web-dev-qa-db-ja.com

引数の型チェックPython

時々Pythonの引数をチェックする必要があります。たとえば、ネットワーク内の他のノードのアドレスを生の文字列アドレスまたはクラスNode =他のノードの情報をカプセル化します。

Type()関数を次のように使用します:

    if type(n) == type(Node):
        do this
    Elif type(n) == type(str)
        do this

これはこれを行うのに良い方法ですか?

更新1:Python 3には関数パラメーターの注釈があります。これらはツールを使用した型チェックに使用できます。- http://mypy-lang.org/

38
Xolve

isinstance()を使用します。サンプル:

if isinstance(n, unicode):
    # do this
Elif isinstance(n, Node):
    # do that
...
109
Johannes Weiss
>>> isinstance('a', str)
True
>>> isinstance(n, Node)
True
13
SilentGhost

いいえ、Pythonの引数をタイプチェックする必要はありません。never必要です。

コードがアドレスをrawstringまたはNodeオブジェクトとして受け入れる場合、デザインは破損します。

これは、自分のプログラムでオブジェクトのタイプがまだわからない場合、すでに何か間違ったことをしているという事実から来ています。

型チェックはコードの再利用を傷つけ、パフォーマンスを低下させます。渡されるオブジェクトのタイプに応じて異なることを実行する関数を使用すると、バグが発生しやすくなり、動作の理解と保守が難しくなります。

次のsanerオプションがあります。

  1. Rawstringsを受け入れるNodeオブジェクトコンストラクター、またはNodeオブジェクト内のストリングを変換する関数を作成します。渡された引数がNodeオブジェクトであると仮定して関数を作成します。そうすれば、文字列を関数に渡す必要がある場合は、次のようにします。

    _myfunction(Node(some_string))
    _

    それはあなたの最良の選択肢です、それはきれいで、理解しやすく、維持しやすいです。コードを読んでいる人はすぐに何が起こっているかを理解し、タイプチェックする必要はありません。

  2. 2つの関数を作成します。1つはNodeオブジェクトを受け入れ、もう1つはrawstringsを受け入れます。最も便利な方法で、一方を他方で内部的に呼び出すことができます(_myfunction_str_はNodeオブジェクトを作成して_myfunction_node_を呼び出すことができます).

  3. Nodeオブジェクトに___str___メソッドを持たせ、関数内で、受け取った引数でstr()を呼び出します。そうすれば、常に強制によって文字列を取得できます。

いずれの場合でも、typecheckしないでください。これは完全に不要であり、欠点のみがあります。代わりに、タイプチェックする必要のない方法でコードをリファクタリングします。短期的にも長期的にも、そうすることでのみ利益が得られます。

8
nosklo

「ジェネリック関数」-与えられた引数に基づいて異なる振る舞いをしているように聞こえます。別のオブジェクトのメソッドを呼び出すときに別の関数を取得する方法に少し似ていますが、関数を検索するために最初の引数(オブジェクト/自己)を使用するのではなく、代わりにすべての引数を使用します。

Turbogearsは、このようなものを使用して、オブジェクトをJSONに変換する方法を決定します-正しく思い出せば。

IBMの記事 この種のことのためにディスパッチャーパッケージを使用する方法があります。

その記事から:

import dispatch
@dispatch.generic()
def doIt(foo, other):
    "Base generic function of 'doIt()'"
@doIt.when("isinstance(foo,int) and isinstance(other,str)")
def doIt(foo, other):
    print "foo is an unrestricted int |", foo, other
@doIt.when("isinstance(foo,str) and isinstance(other,int)")
def doIt(foo, other):
    print "foo is str, other an int |", foo, other
@doIt.when("isinstance(foo,int) and 3<=foo<=17 and isinstance(other,str)")
def doIt(foo, other):
    print "foo is between 3 and 17 |", foo, other
@doIt.when("isinstance(foo,int) and 0<=foo<=1000 and isinstance(other,str)")
def doIt(foo, other):
    print "foo is between 0 and 1000 |", foo, other
6
John Montgomery

必要に応じて、try catchを使用して型チェックを行うこともできます。

def my_function(this_node):
    try:
        # call a method/attribute for the Node object
        if this_node.address:
             # more code here
             pass
    except AttributeError, e:
        # either this is not a Node or maybe it's a string, 
        # so behavior accordingly
        pass

この例はBeginning Pythonで2番目のジェネレーター(私のエディションの197ページ)で見ることができ、Python Cookbookを信じています。多くの場合、AttributeErrorまたはTypeErrorをキャッチする方が簡単で、明らかに高速です。また、特定の継承ツリーに関連付けられていないため、この方法で最適に機能する場合があります(たとえば、オブジェクトはNodeであるか、Nodeと同じ動作をする他のオブジェクトである可能性があります)。

6
Rob