type()とisinstance()の違いは何ですか?


1248

これら2つのコードフラグメントの違いは何ですか?

使用type()

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()

使用isinstance()

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()

注:そうでない場合strunicode(あなただけをチェックできる場所basestring)には、複数のタイプに対してチェックするためにタプルを使用することができます。かどうかを確認するにsomethingは、intまたはをstr使用しますisinstance(something, (int, str))
xuiqzy

回答:


1271

他の(すでに良い!)回答の内容を要約するisinstanceと、継承に対応します(派生クラスインスタンスも基本クラスのインスタンスです)が等しいかtypeどうかを確認します(型の同一性を要求し、インスタンスを拒否します)サブタイプ、別名サブクラス)。

通常は、Pythonで、あなたはサポートの継承にあなたのコードをしたい、(継承は非常に便利であることから、それを使用してからあなたを使用してコードを停止するために悪いだろう!)もちろん、そうisinstanceの身元チェックするよりも少ない悪いですtype、それシームレスにサポートしているので、sが継承。

それisinstance良いことではありません、心に留めておいてください。型の等価性をチェックするよりも悪いことではありません。通常のPythonicで推奨される解決策は、ほぼ常に「ダックタイピング」です。ある種の望ましい型であるかのように引数使用してみてください。引数が実際にそうでなかった場合に発生する可能性のあるすべての例外をキャッチするtry/ exceptステートメントでそれを実行してくださいタイプ(または他の任意のタイプをうまくダックで模倣する;-)、そしてexcept句で他のことを試してください(引数を「あたかも」他のタイプのように使用して)。

basestring ある、しかし、存在は非常に特殊なケース組み込みタイプのみ使用できるようにisinstance(両方strunicodeサブクラスをbasestring)。文字列はシーケンスです(ループし、インデックスを付け、スライスすることもできます...)が、通常は「スカラー」型として扱いたいと思います。文字列(そしておそらく他のスカラー型、つまりループできないもの)を1つの方法で、すべてのコンテナー(リスト、セット、ディクショナリなど)を別の方法で、そしてbasestringさらにisinstanceそれを行うのに役立ちます。これの全体的な構造イディオムは次のようなものです:

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)

これbasestringは、抽象基本クラス( "ABC")と言えます。サブクラスに具体的な機能はありませんが、主にで使用される「マーカー」として存在しisinstanceます。その概念は、Pythonで一般化しつつあるPEP 3119が受け入れられ、Python 2.6および3.0から実装されて以来、Pythonで明らかに成長しています。

PEPは、ABCがダックタイピングの代わりになることがよくある一方で、一般的にそれを行うための大きなプレッシャーはないことを明らかにしています(ここを参照)。ただし、最近のPythonバージョンに実装されたABCは、さらに優れた機能を提供します。isinstance(およびissubclass)は、「[派生クラス]のインスタンス」以上のものを意味するようになりました(特に、任意のクラスをABCに「登録」して、サブクラスとして表示し、そのインスタンスをABCのインスタンスとして表示します); ABCは、テンプレートメソッドのデザインパターンアプリケーションを介して、実際のサブクラスに非常に自然な方法で追加の利便性を提供することもできます(ABCとは関係なく、一般的に、具体的にはPythonでのTM DPの詳細については、ここここ [[パートII]]を参照してください)。 。

Python 2.6で提供されるABCサポートの基本的な仕組みについては、こちらを参照してください。非常によく似た3.1バージョンについては、こちらを参照してください。どちらのバージョンでも、標準ライブラリモジュールコレクション(3.1バージョンです。非常に類似した2.6バージョンについては、こちらを参照してください)は、いくつかの便利なABCを提供します。

この回答の目的のために、ABCについて保持する重要な点は(UserDict.DictMixinなどのミックスインクラスの従来のPythonの代替と比較して、TM DP機能の間違いなくより自然な配置を超えて)、それらがisinstance(およびissubclass)はるかに多くなることです(Python 2.6以降では)以前よりも魅力的で普及しているため(2.5以前)、そのため、対照的に、最近のPythonバージョンでは、型の等価性のチェックを、以前よりもさらに悪い方法にしています。


9
「インスタンスが適切であるということではありません。念のために言っておきます。型の等価性をチェックするよりも悪いことではありません。通常、Pythonic、推奨されるソリューションはほぼ常に「ダックタイピング」です。これはかなり限定的なビューです。たとえば、型が文法を反映するインタープリターでisinstance()を使用する非常に良いケースがあります。「Pythonic」であることはすべてではありません!
Gene Callahan

2
basestringは、Python 3には使用できません
erobertc

@GeneCallahanは非常に良いケースがあるため、言われたことが一般的なルールではないという意味ではありません。事前に型をチェックすることは間違いなくその場所にありますが、カモをたわませることでほとんどのケースをより柔軟かつ効率的にカバーできることに同意します。
エリックエドローマー

@ erobertc、Python 3.0の新機能によると、「組み込みのベースストリング抽象型は削除されました。代わりにstrを使用してください。」
神経突起

345

isinstanceこれtypeはできないことを達成する例です:

class Vehicle:
    pass

class Truck(Vehicle):
    pass

この場合、トラックオブジェクトは車両ですが、次のようになります。

isinstance(Vehicle(), Vehicle)  # returns True
type(Vehicle()) == Vehicle      # returns True
isinstance(Truck(), Vehicle)    # returns True
type(Truck()) == Vehicle        # returns False, and this probably won't be what you want.

つまり、isinstanceサブクラスについても同様です。

また参照してください:Pythonでオブジェクトのタイプを比較する方法?


143
isInstanceの動作を望まない場合があるため、「より良い」ものはないと主張します。彼らはただ違うことをします。
philgo20 2012年

27
-1「インスタンスよりタイプより良い」は誤解を招くコメントなので。それは「同じように理解されてtype使用し、推奨されませんisinstance一見代わりに」。たとえば、私が欲しかったのは正確にtype()チェックすることでしたが、そのため、しばらくの間、誤解されました(そして少しデバッグする必要がありました)。
ceremcem

8
これは動作が異なることを示す良い例ですが、私は特に必要type()としないケースに出くわしましたisinstance()。1つは良くありません。彼らは別のものです。
EL_DON 2017

103

isinstance()type()Pythonの違いは?

による型チェック

isinstance(obj, Base)

サブクラスのインスタンスと複数の可能なベースを許可します:

isinstance(obj, (Base1, Base2))

一方、型チェック

type(obj) is Base

参照されるタイプのみをサポートします。


補足として、isおそらくより適切です

type(obj) == Base

クラスはシングルトンだからです。

型チェックを回避する-ポリモーフィズム(ダックタイピング)を使用する

Pythonでは、通常、引数に任意の型を許可し、それを期待どおりに処理します。オブジェクトが期待どおりに動作しない場合は、適切なエラーが発生します。これは多型として知られており、アヒルのタイピングとしても知られています。

def function_of_duck(duck):
    duck.quack()
    duck.swim()

上記のコードが機能する場合、引数はアヒルであると推定できます。したがって、アヒルの実際のサブタイプである他のものを渡すことができます:

function_of_duck(mallard)

またはそれはアヒルのように機能します:

function_of_duck(object_that_quacks_and_swims_like_a_duck)

私たちのコードはまだ機能します。

ただし、明示的に型チェックを行うことが望ましい場合があります。おそらく、さまざまな種類のオブジェクトを扱うために賢明なことがあるでしょう。たとえば、Pandas Dataframeオブジェクトは、辞書またはレコードから構築できます。このような場合、コードは、適切に処理できるように、取得する引数のタイプを知る必要があります。

したがって、質問に答えるには:

isinstance()type()Pythonの違いは?

違いを示すことができます:

type

関数が特定の種類の引数(コンストラクターの一般的な使用例)を受け取った場合、特定の動作を保証する必要があるとしましょう。次のようなタイプをチェックすると:

def foo(data):
    '''accepts a dict to construct something, string support in future'''
    if type(data) is not dict:
        # we're only going to test for dicts for now
        raise ValueError('only dicts are supported for now')

サブクラスであるdictを渡そうとするとdict(可能な限り、コードがLiskov Substitutionの原則に従うことを期待している場合は、そのサブタイプをタイプに置き換えることができます)、コードが壊れます!:

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

エラーが発生します!

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
ValueError: argument must be a dict

isinstance

しかし、を使用するとisinstance、Liskov Substitutionをサポートできます!:

def foo(a_dict):
    if not isinstance(a_dict, dict):
        raise ValueError('argument must be a dict')
    return a_dict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

戻り値 OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

抽象基本クラス

実際に、私たちはさらに良いことができます。collectionsは、さまざまなタイプに最小限のプロトコルを適用する抽象基本クラスを提供します。私たちのケースでは、Mappingプロトコルのみを期待している場合、次のことができ、コードはさらに柔軟になります。

from collections import Mapping

def foo(a_dict):
    if not isinstance(a_dict, Mapping):
        raise ValueError('argument must be a dict')
    return a_dict

コメントへの応答:

タイプを使用して複数のクラスをチェックすることができることに注意してください type(obj) in (A, B, C)

はい、型の等価性をテストできますが、これらの型のみを明確に許可しない限り、上記の代わりに、制御フローに複数のベースを使用します。

isinstance(obj, (A, B, C))

違いは、やはり、isinstanceLiskov置換と呼ばれるプロパティであるプログラムを壊さずに親の代わりに使用できるサブクラスをサポートすることです。

ただし、さらに良いのは、依存関係を逆にし、特定のタイプをまったくチェックしないことです。

結論

したがって、サブクラスの置換をサポートする必要があるため、インスタンスの正確なクラスを本当に知る必要がない限り、ほとんどの場合、型チェックを避け、型チェックをtype優先isinstanceする必要があります。


をチェックしisinstance(instance, y)て使用するyour_module.pyがありfrom v.w.x import y、そのチェックをインポートしたが、インスタンス化instanceするfrom x import yと、yがyour_module.pyにインポートされた方法の代わりに使用された場合、同じクラスであっても、isinstanceチェックは失敗します。
toonarmycaptain

64

サブクラスを適切に処理するため、後者が推奨されます。実際、isinstance()の2番目のパラメーターはタプルになる可能性があるため、例はさらに簡単に記述できます。

if isinstance(b, (str, unicode)):
    do_something_else()

または、basestring抽象クラスを使用します。

if isinstance(b, basestring):
    do_something_else()


9

実際の使用法の違いは、それらの処理方法booleansです。

TrueそしてFalseちょうどそれが平均キーワードである10pythonで。したがって、

isinstance(True, int)

そして

isinstance(False, int)

どちらも戻りTrueます。両方のブール値は整数のインスタンスです。type()ただし、より賢いです。

type(True) == int

を返しますFalse


0

実際の違いについては、で確認できますcodeが、のデフォルトの動作の実装は見つかりませんisinstance()

ただし、__ instancecheck__に従って、同様のabc .__ instancecheck__を取得できます。

上からabc.__instancecheck__、以下のテストを使用した後:

# file tree
# /test/__init__.py
# /test/aaa/__init__.py
# /test/aaa/aa.py
class b():
pass

# /test/aaa/a.py
import sys
sys.path.append('/test')

from aaa.aa import b
from aa import b as c

d = b()

print(b, c, d.__class__)
for i in [b, c, object]:
    print(i, '__subclasses__',  i.__subclasses__())
    print(i, '__mro__', i.__mro__)
    print(i, '__subclasshook__', i.__subclasshook__(d.__class__))
    print(i, '__subclasshook__', i.__subclasshook__(type(d)))
print(isinstance(d, b))
print(isinstance(d, c))

<class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'>
<class 'aaa.aa.b'> __subclasses__ []
<class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>)
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasses__ []
<class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>)
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>]
<class 'object'> __mro__ (<class 'object'>,)
<class 'object'> __subclasshook__ NotImplemented
<class 'object'> __subclasshook__ NotImplemented
True
False

私はこの結論を得ますtype

# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one 
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__

の場合isinstance

# guess from `abc.__instancecheck__`
return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)})

ところでrelative and absolutely import、使用を混合しない方が良いですabsolutely import、project_dirから使用してください(によって追加sys.path

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.