web-dev-qa-db-ja.com

isinstance(foo、bar)vs type(foo)is bar

本当に意味論の問題です。

最近まで、構造体で型チェックを行う必要がある場合は、type(obj) is list etを使用していました。 al。しかし、SOに参加して以来、みんなに気づきました(そして[〜#〜] everyone [〜#〜])は代わりにisinstance(obj,list)を使用します。これらは同義語のようであり、timeitはそれらの間のほぼ同一の速度を示します。

_def a(): return type(list()) is list
def b(): return isinstance(list(),list)

from timeit import timeit
timeit(a)
# 0.5239454597495582
timeit(b)
# 0.5021292075273176
_

実際、disでさえ、_type is_の_COMPARE_OP_を除いて、同義語であることに同意します

_from dis import dis

dis(a)
# 2           0 LOAD_GLOBAL              0 (type) 
#             3 LOAD_GLOBAL              1 (list) 
#             6 CALL_FUNCTION            0 (0 positional, 0 keyword pair) 
#             9 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
#            12 LOAD_GLOBAL              1 (list) 
#            15 COMPARE_OP               8 (is) 
#            18 RETURN_VALUE

dis(b)
# 2           0 LOAD_GLOBAL              0 (isinstance)
#             3 LOAD_GLOBAL              1 (list) 
#             6 CALL_FUNCTION            0 (0 positional, 0 keyword pair) 
#             9 LOAD_GLOBAL              1 (list) 
#            12 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
#            15 RETURN_VALUE 
_

率直に言って、if type(foo) is list:よりもif isinstance(foo,list):の方が読みやすいと思います。最初は基本的に単なる疑似コードで、2番目はいくつかの関数を呼び出します(isinstanceになるために毎回検索する必要があります)またはinstanceof)を引数とともに使用します。これは型キャストのようではなく、isinstance(a,b)baのインスタンスであるかどうか、またはその逆であるかどうかを確認する明示的な方法はありません。

私は この質問 から理解します。継承についてはより良いので、isinstanceを使用します。 type(ClassDerivedFromList) is listは成功しますが、isinstance(ClassDerivedFromList,list)は失敗します。しかし、私が常にBASE OBJECTであるべきものをチェックしている場合、_type is_を実行することで本当に何が失われますか?

26
Adam Smith

私が常に基本オブジェクトであるべきものをチェックしている場合、タイプを行うことで本当に何を失うのですか?

まあ、それはあなたがあなたの質問で完全に文書化された答えを与えるのがいいので、あなたの答えはあなたが失うことですnothing!よく言及したように、isinstance()が必要なのは、特定のクラスの継承を他のクラスと比較してチェックするときだけです。 type()は、インスタンスが特定の基本型の正確にかどうかを確認するためにのみ使用されます。

17
zmo

継承の問題以外に、isinstanceを使用すると、複数の型をテストする機能も失われます。例えば:

def chk(typ):
    if not isinstance(typ, (str, int)):
        raise ValueError('typ must be string or int')
    ...
6
user590028

組み込み型関数のPythonドキュメント は、型(引数が1つ)とisinstanceの違いに関する明確なガイダンスを提供します。

1つの引数で、オブジェクトのタイプを返します。戻り値はタイプオブジェクトであり、通常はobject。classによって返されるオブジェクトと同じです。 isinstance()組み込み関数は、サブクラスを考慮に入れるため、オブジェクトのタイプのテストに推奨されます。

例として、モジュールdiamondの以下の継承階層を見てください。

enter image description here

次に、モジュールdiamondに基づく以下のpythonコンソール出力を見てください。

enter image description here

ドキュメンテーションに従って、それはより用途が広く、より広い範囲のシナリオをカバーできます。 OPの元の質問に関して-パフォーマンス特性は、一方を他方よりも支持する正当な理由として述べられていませんでした。どちらも読みやすかった。

(回答者の言葉で)についての説明を含むより詳細な議論のために、なぜ型の等価性をチェックすることは最近のPythonすでに使用されているバージョンよりも新しいバージョンです。」、これをご覧ください answer

1
arcseldon

あなたの質問への答えは:
いいえ、継承されたクラスをテストする機能を失うため、明確な基本クラスをチェックしていることになります。

そして、IMO isinstanceは読みやすく、Pythonでは読みやすさを重視しています。

PS:タイミングに大きな違いがあります(Python 3.3))

      type: 0.5241982917936874  
isinstance: 0.46066255811928847
0
pradyunsg