関数 - python type型
type()とisinstance()の違いは何ですか? (4)
Pythonの
isinstance()
とtype()
違いは?
型チェック
isinstance(obj, Base)
サブクラスと複数の可能なベースのインスタンスを許可します。
isinstance(obj, (Base1, Base2))
タイプチェックは
type(obj) is Base
参照される型のみをサポートします。
sidenoteとして、これはおそらく
type(obj) == Base
クラスはシングルトンであるためです。
型チェックを避ける - 多態性(ダックタイピング)を使用する
Pythonでは、通常、引数の型を許可し、期待どおりに処理し、オブジェクトが期待どおりに動作しない場合は、適切なエラーを発生させます。 これは、多型(duck typing)としても知られています。
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オブジェクトは、dicts またはレコードから構築できます。 そのような場合、あなたのコードは、それが適切に処理できるようにどのような引数が得られているのかを知る必要があります。
だから、質問に答えるには:
Pythonのisinstance()
とtype()
違いは?
違いを実証できるようにする:
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
を使う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は
type(obj) in (A, B, C)
を使って複数のクラスに対して検査するのに使うことができます。
はい、あなたはタイプの平等のためにテストすることができますが、上記の代わりに、それらのタイプを特に許可しない限り、コントロールフローのために複数のベースを使用してください:
isinstance(obj, (A, B, C))
違いは、 isinstance
が、プログラムを破棄することなく、親に代わることができるサブクラス、Liskov置換として知られているプロパティをサポートしていることです。
しかし、あなたの依存関係を逆転させ、特定の型を全くチェックしないでください。
結論
したがって、サブクラスの置換をサポートしたいので、ほとんどの場合、型の型チェックを避け、インスタンスの正確なクラスを実際に知る必要がない限り、型検査をisinstance
ことをおisinstance
します。
これら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()
Pythonのドキュメントによれば、ここには文があります:
8.15。 types - 組み込み型の名前
Python 2.2以降、
int()
やstr()
などの組込みファクトリ関数も対応する型の名前です。
したがって、 isinstance()
はtype()
よりも優先されるべきです。
サブクラスを適切に処理するため、後者が優先されます。 実際には、 isinstance()
の2番目のパラメータがタプルである可能性があるため、 isinstance()
さらに簡単に書くことができます。
if isinstance(b, (str, unicode)):
do_something_else()
または、 basestring
抽象クラスを使用しbasestring
。
if isinstance(b, basestring):
do_something_else()
他の(すでに良い!)回答の内容を要約すると、継承のためのisinstance
(派生クラスのインスタンスも基本クラスのインスタンスです)では、 type
等価性をチェックするのではなく、サブタイプのインスタンス、AKAサブクラスを拒否します)。
通常、Pythonでは、継承をサポートするコードが必要です(継承はとても便利なので、コードを使用してコードを使用するのを止めるのは悪いです)ので、 isinstance
はtype
sのIDをチェックするよりも悪くありません継承をシームレスにサポートします。
isinstance
が良いことではなく、タイプの平等をチェックすることよりも悪いことではありません。 通常のPythonの優先ソリューションは、ほとんど常に "ダックタイピング"です:引数が特定のタイプのものであるかのように引数を使用してtry
実際には引数がない場合に発生するすべての例外をキャッチするtry
/ except
文で行います(またはそれ以外の型をうまく模倣する;-)、 except
節では、他の型を試してみてください。
しかし、 basestring
は非常に特殊なケースです。 basestring
、 isinstance
( str
とunicode
サブクラスのbasestring
両方)を使用できるようにするためだけに存在する組み込みタイプです。 文字列はシーケンスです(ループしたり、インデックスを付けたり、スライスしたりできます)が、一般的にはスカラー型として扱いたいと思っています。すべてのコンテナ(リスト、セット、dicts、...)を別の方法でストリング(そしておそらく他のスカラータイプ、つまりループできないスカラータイプ)とbasestring
plus isinstance
このイディオムのようなものです:
if isinstance(x, basestring)
return treatasscalar(x)
try:
return treatasiter(iter(x))
except TypeError:
return treatasscalar(x)
ベース basestring
は抽象基本クラス (ABC)です。サブクラスには具体的な機能はありませんが、主にisinstance
で使用するための「マーカー」として存在しisinstance
。 この概念は、明らかにPythonで成長しているものです。一般化を紹介するPEP 3119が受け入れられ、Python 2.6および3.0から実装されています。
PEPは、ABCはダックタイピングに代わることが多いが、一般的にそれを行うという大きな圧力はないことを明確にしている( here参照)。 最近のPythonバージョンで実装されているABCは特別な機能を提供しています: isinstance
(およびissubclass
)は、単に "派生クラスのインスタンス"以上を意味することができます(特に、ABCでどのクラスも "サブクラスとして表示され、そのインスタンスはABCのインスタンスとして表示されます)。 また、ABCは、テンプレートメソッド設計パターンアプリケーション( hereでは、TM DP、一般的には特にPythonで、ABCとは独立しています)については、実際のサブクラスに非常に自然な方法で追加の利便性を提供することができます。 。
Python 2.6で提供されているABCサポートの根本的な仕組みについては、 hereご覧here 。 彼らの3.1バージョンでは、非常に似て、 here参照してhere 。 どちらのバージョンでも、標準ライブラリモジュールcollections (これは3.1バージョンです - これに類似した2.6バージョン用here )は、いくつかの有用なABCを提供します。
この答えの目的のために、ABC( UserDict.DictMixinようなmixinクラスの古典的なPythonの代替手段と比較して、TM DP機能のために間違いなく自然な配置を超えて)を維持するための重要なことは、 isinstance
(およびissubclass
) Python 2.6以降では2.5以前のバージョンよりもはるかに魅力的で普及していたため、最近のPythonバージョンでは型の等価性をチェックするのがこれまでの場合よりもさらに厳しくなりました。