web-dev-qa-db-ja.com

Python変数の型をチェックするための最善の(慣用的な)方法は何ですか?

私はPythonの変数が文字列なのか辞書なのかを知る必要があります。次のコードに何か問題がありますか?

if type(x) == type(str()):
    do_something_with_a_string(x)
Elif type(x) == type(dict()):
    do_somethting_with_a_dict(x)
else:
    raise ValueError

更新:私はavisserの答えを受け入れました(type(x) isよりisinstanceが好まれる理由が説明されたら私の考えは変わりますが)。

しかし、if/Elif/elseシリーズよりdict(case文として)を使うほうがきれいだと私に思い出させてくれたnakedfanaticに感謝します。

ユースケースについて詳しく説明しましょう。変数が文字列の場合は、リストに入れる必要があります。それが口述であれば、私はユニークな値のリストが必要です。これが私が思いついたものです:

def value_list(x):
    cases = {str: lambda t: [t],
             dict: lambda t: list(set(t.values()))}
    try:
        return cases[type(x)](x)
    except KeyError:
        return None

isinstanceが優先される場合、どのようにしてこのvalue_list()関数を書きますか?

288
Daryl Spitzer

誰かがあなたの関数にUnicode文字列を渡すとどうなりますか?それともdictから派生したクラス?それとも辞書風のインターフェースを実装するクラス?次のコードは最初の2つのケースをカバーしています。 Python 2.6を使用している場合は、 ABC PEP のようにdictの代わりに collections.Mapping を使用することをお勧めします。

def value_list(x):
    if isinstance(x, dict):
        return list(set(x.values()))
    Elif isinstance(x, basestring):
        return [x]
    else:
        return None
315
Suraj

type(dict())は、「新しい辞書を作成してから、その種類が何であるかを調べます」と述べています。単に「口述」と言う方が早いです。しかし、単に型をチェックしたいのならば、もっと慣用的な方法はisinstance(x, dict)です。

isinstanceにはサブクラスも含まれていることに注意してください(thanks Dustin )。

class D(dict):
    pass

d = D()
print("type(d) is dict", type(d) is dict)  # -> False
print("isinstance (d, dict)", isinstance(d, dict))  # -> True
57
Ken

pythonの組み込み型には組み込みの名前があります。

>>> s = "hallo"
>>> type(s) is str
True
>>> s = {}
>>> type(s) is dict
True

ところでis演算子に注意してください。ただし、型チェックは(それを呼び出したい場合)、通常、try-except節で型固有のテストをラップすることによって行われます。これは、それほど重要な変数の型ではありませんそれと一緒かどうか。

34
Albert Visser

isinstanceは、オブジェクトインスタンスをそのスーパークラスと比較したときにもTrueと評価されるため、typeよりも優先されます。つまり、dictやstrのサブクラスで使用するために古いコードを特別に記述する必要はなくなります。

例えば:

 >>> class a_dict(dict):
 ...     pass
 ... 
 >>> type(a_dict()) == type(dict())
 False
 >>> isinstance(a_dict(), dict)
 True
 >>> 

もちろん、この振る舞いを望まない状況もあるかもしれませんが、望んでいる状況よりもはるかに一般的ではありません。

19
Dirk Stoop

「アヒルのように歩くならば、それはアヒルのように震え、そのアヒル」 - 私は私がアヒルのタイピングアプローチに行くと思います。これにより、文字列がUnicodeかASCIIかを気にする必要がなくなります。

これが私がやることです:

In [53]: s='somestring'

In [54]: u=u'someunicodestring'

In [55]: d={}

In [56]: for each in s,u,d:
    if hasattr(each, 'keys'):
        print list(set(each.values()))
    Elif hasattr(each, 'lower'):
        print [each]
    else:
        print "error"
   ....:         
   ....:         
['somestring']
[u'someunicodestring']
[]

ここの専門家は、このタイプのダックタイピングの使用法についてコメントすることを歓迎します。私はそれを使用していますが、最近その背後にある正確な概念を紹介され、とても興奮しています。それで、やり過ぎがやり過ぎかどうかを知りたいのです。

8
JV.

私はそれが実際にするのが好ましいかもしれないと思います

if isinstance(x, str):
    do_something_with_a_string(x)
Elif isinstance(x, dict):
    do_somethting_with_a_dict(x)
else:
    raise ValueError

2あなたのコードのどちらかに応じて2代替フォームは、おそらくそれよりも優れていると考えられています。一つはあなたが跳躍する前に見ないことです

try:
  one, two = tupleOrValue
except TypeError:
  one = tupleOrValue
  two = None

もう1つのアプローチはGuidoによるもので、コードをよりオープンエンドにする関数オーバーロードの一種です。

http://www.artima.com/weblogs/viewpost.jsp?thread=155514

6
Ed.

あなたはタイプチェックをチェックしたくなるかもしれません。 http://pypi.python.org/pypi/typecheck

Python用の型チェックモジュール

このパッケージは、Pythonの関数、メソッド、そしてジェネレータのための強力なランタイム型チェック機能を提供します。カスタムプリプロセッサや言語の変更を必要としないで、typecheckパッケージはプログラマーと品質保証エンジニアが彼らのコードへの入力とそこからの出力に関して正確な主張をすることを可能にします。

3

それはうまくいくはずです - だから、あなたのコードには何の問題もありません。しかし、それは辞書でも可能です。

{type(str()): do_something_with_a_string,
 type(dict()): do_something_with_a_dict}.get(type(x), errorhandler)()

もう少し簡潔にして、Pythonicを言わないでください。


編集.. Hevis Avisserのアドバイス。コードもこのように動作し、見栄えがよくなります。

{str: do_something_with_a_string,
 dict: do_something_with_a_dict}.get(type(x), errorhandler)()
3
nakedfanatic

私は別の方法を使ってきました:

from inspect import getmro
if (type([]) in getmro(obj.__class__)):
    # This is a list, or a subclass of...
Elif (type{}) in getmro(obj.__class__)):
    # This one is a dict, or ...

しかし、なぜ私がisinstanceの代わりにこれを使ったのか思い出せません…。

1

*sigh*

いいえ、pythonの型チェック引数は必要ありません。 決して必要ない

コードが文字列または辞書オブジェクトを受け入れる場合、デザインは壊れています。

それはあなたがあなた自身のプログラムの中のオブジェクトのタイプをまだ知らないならば、あなたはすでに何か別のことをしているという事実から来ています。

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

次のようなより安全なオプションがあります。

1)値を固有の値のリストに変換する関数unique_valuesを作成します。

def unique_values(some_dict):
    return list(set(some_dict.values()))

渡された引数が常にリストであるとあなたの関数に仮定させます。そのように、あなたが関数に文字列を渡す必要があるならば、あなたはただするだけです:

myfunction([some_string])

あなたがそれを辞書に渡す必要があるならば、あなたはそうします:

myfunction(unique_values(some_dict))

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

2)文字列のリストを受け付ける機能と辞書を受け付ける機能の2つの機能を作成します。最も便利な方法で、一方を他方の呼び出しにすることができます(myfunction_dictは文字列のリストを作成してmyfunction_listを呼び出すことができます)。

いずれにせよ、はタイプチェックをしないでください。それは完全に不要で、欠点しかありません。タイプチェックする必要がないように、代わりにコードをリファクタリングしてください。あなたはそうすることによって、短期的にも長期的にも利益を得るだけです。

0
nosklo