これら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()
他の(すでに良い!)答えの内容を要約すると、isinstance
は継承(派生クラスのインスタンスis _インスタンスも)を考慮しますが、type
の等価性はチェックしません(それはタイプのアイデンティティを要求し、サブタイプのインスタンス、AKAサブクラスを拒否します)。
通常、Pythonでは、当然、自分のコードで継承をサポートする必要があります(継承は非常に便利なので、コードを使用しないようにするのは悪いことです)。isinstance
は、シームレスにtype
sのIDをチェックするよりも劣りません。継承をサポートします。
isinstance
がgoodであるというわけではありません、あなたに注意してください - それは単に型の同等性をチェックするよりより悪いです。通常のPythonicの推奨される解決策は、ほとんど常に「ダックタイピング」です。引数{あたかもを使用してみてください。それは、特定の希望の型で、try
except
ステートメントで実行してください。引数は実際にはその型のものではなく(または他の型のものをうまく模倣している;-)、except
句で(他の型の引数であるかのように)引数を使用してください。
basestring
は ですが、isinstance
(str
とunicode
の両方のサブクラスbasestring
)を使用できるようにするために存在する組み込み型 only です。文字列はシーケンスです(ループしたり、インデックスを付けたり、スライスしたりすることができます)。ただし、通常は "スカラー"型として扱う必要があります。すべての種類の文字列を扱うにはやや不便です(ただしかなり頻繁に使用されるケース)。文字列(そしておそらく他のスカラ型、つまりループできないもの)、ある意味ではすべてのコンテナ(リスト、セット、辞書など)、そしてbasestring
とisinstance
はそれを支援します - 全体的な構造この慣用句の意味は次のとおりです。
if isinstance(x, basestring)
return treatasscalar(x)
try:
return treatasiter(iter(x))
except TypeError:
return treatasscalar(x)
basestring
は抽象基本クラス( "ABC")であると言えます - サブクラスに具体的な機能はありませんが、主にisinstance
で使用するための "マーカー"として存在します。それを一般化した_/PEP 3119 が受け入れられ、Python 2.6と3.0から実装されてきたため、この概念はPythonで明らかに成長しているものです。
PEPは、ABCがしばしばアヒルの型付けの代わりになることができる間、それをするために大きな圧力が通常ないことをそれを明確にします( here を見てください)。最近のPythonのバージョンで実装されているABCは、しかし、さらに優れた機能を提供します。isinstance
(およびissubclass
)は、単なる「派生クラス」以上の意味を持つことができます。サブクラスとして表示され、そのインスタンスはABCのインスタンスとして表示されます。また、ABCは、Template Methodデザインパターンアプリケーションを介して、非常に自然な方法で実際のサブクラスに特別な利便性を提供することもできます(TM DPの一般的な詳細については、 here および here [[II]]を参照)。特にPythonでは、ABCとは無関係です。
Python 2.6で提供されているABCサポートの基本的な仕組みについては、 here を参照してください。その3.1バージョンについては、非常によく似ていますが、 here を参照してください。どちらのバージョンでも、標準ライブラリモジュール collections (これは3.1バージョンです。これと非常によく似た2.6バージョンについては、 here を参照してください)には、いくつかの便利なABCがあります。
この答えの目的のために、 UserDict.DictMixin のようなmixinクラスの古典的なPythonの代替手段と比較して、ABCについて保持するべき重要なことは(TM DP機能のための間違いなく自然な配置を超えて)それらがisinstance
を作ることです。 (そしてissubclass
)は(2.5とそれ以前の)以前よりずっと魅力的で普及しています、そしてそれとは対照的に、最近のPythonバージョンでは型の同等性のチェックを今よりもっと悪い習慣にしますあった。
これはisinstance
がtype
ができない何かを達成する例です:
class Vehicle:
pass
class Truck(Vehicle):
pass
この場合、トラックオブジェクトはVehicleですが、次のようになります。
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でオブジェクトの種類を比較する方法?
Pythonの
isinstance()
とtype()
の違いは?
と型チェック
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オブジェクトはdicts または recordsから構成できます。そのような場合、あなたのコードはそれが適切にそれを扱うことができるようにそれがどんなタイプの引数を得ているかを知る必要があります。
それで、質問に答えるために:
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
のサブクラスである辞書を渡しようとすると(コードが 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)
を使って複数のクラスに対してチェックするためにtypeを使うことができることに注意すべきです。
はい、タイプの同等性をテストすることはできますが、上記の代わりに、これらのタイプのみを許可するのでない限り、制御フローに複数の基数を使用してください。
isinstance(obj, (A, B, C))
ここでも違いは、isinstance
が、プログラムを壊すことなく親の代わりになることができるサブクラスをサポートすることです。これはLiskovの置換として知られています。
ただしさらに良いことに、依存関係を逆にして、特定の型をチェックしないでください。
そのため、サブクラスの置き換えをサポートしたいので、ほとんどの場合、type
による型チェックを避け、isinstance
による型チェックを優先します - 実際にインスタンスの正確なクラスを知る必要がない限り。
後者はサブクラスを適切に処理するため、推奨されます。実際には、isinstance()
の2番目のパラメータはTupleかもしれないので、あなたの例はさらにもっと簡単に書くことができます:
if isinstance(b, (str, unicode)):
do_something_else()
あるいは、basestring
抽象クラスを使用します。
if isinstance(b, basestring):
do_something_else()
Pythonのドキュメントによると、ここに文があります:
8.15。 types - 組み込み型の名前
Python 2.2からは、
int()
やstr()
のような組み込みのファクトリ関数もまた対応する型の名前です。
そのため isinstance()
は type()
より優先されるべきです。
本当の違いは、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
を使うことを混ぜないほうがよい、project_dirからabsolutely import
を使う(sys.path
によって追加される)
実用的な使用法の違いは、それらがbooleans
をどのように処理するかです。
True
とFalse
は、pythonで1
と0
を意味する単なるキーワードです。したがって、
isinstance(True, int)
そして
isinstance(False, int)
両方ともTrue
を返します。両方のブール値は整数のインスタンスです。 type()
は、しかし、もっと賢いです:
type(True) == int
False
を返します。