web-dev-qa-db-ja.com

Type()と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()
1088
abbot

他の(すでに良い!)答えの内容を要約すると、isinstanceは継承(派生クラスのインスタンスis _インスタンスも)を考慮しますが、typeの等価性はチェックしません(それはタイプのアイデンティティを要求し、サブタイプのインスタンス、AKAサブクラスを拒否します)。

通常、Pythonでは、当然、自分のコードで継承をサポートする必要があります(継承は非常に便利なので、コードを使用しないようにするのは悪いことです)。isinstanceは、シームレスにtypesのIDをチェックするよりも劣りません。継承をサポートします。

isinstancegoodであるというわけではありません、あなたに注意してください - それは単に型の同等性をチェックするよりより悪いです。通常のPythonicの推奨される解決策は、ほとんど常に「ダックタイピング」です。引数{あたかもを使用してみてください。それは、特定の希望の型で、tryexceptステートメントで実行してください。引数は実際にはその型のものではなく(または他の型のものをうまく模倣している;-)、except句で(他の型の引数であるかのように)引数を使用してください。

basestringですが、isinstancestrunicodeの両方のサブクラスbasestring)を使用できるようにするために存在する組み込み型 only です。文字列はシーケンスです(ループしたり、インデックスを付けたり、スライスしたりすることができます)。ただし、通常は "スカラー"型として扱う必要があります。すべての種類の文字列を扱うにはやや不便です(ただしかなり頻繁に使用されるケース)。文字列(そしておそらく他のスカラ型、つまりループできないもの)、ある意味ではすべてのコンテナ(リスト、セット、辞書など)、そしてbasestringisinstanceはそれを支援します - 全体的な構造この慣用句の意味は次のとおりです。

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バージョンでは型の同等性のチェックを今よりもっと悪い習慣にしますあった。

1131
Alex Martelli

これはisinstancetypeができない何かを達成する例です:

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でオブジェクトの種類を比較する方法?

302
Peter

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から構成できます。そのような場合、あなたのコードはそれが適切にそれを扱うことができるようにそれがどんなタイプの引数を得ているかを知る必要があります。

それで、質問に答えるために:

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のサブクラスである辞書を渡しようとすると(コードが 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による型チェックを優先します - 実際にインスタンスの正確なクラスを知る必要がない限り。

82
Aaron Hall

後者はサブクラスを適切に処理するため、推奨されます。実際には、isinstance()の2番目のパラメータはTupleかもしれないので、あなたの例はさらにもっと簡単に書くことができます:

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

あるいは、basestring抽象クラスを使用します。

if isinstance(b, basestring):
    do_something_else()
59
John Millikin

Pythonのドキュメントによると、ここに文があります:

8.15。 types - 組み込み型の名前

Python 2.2からは、int()str()のような組み込みのファクトリ関数もまた対応する型の名前です。

そのため isinstance()type() より優先されるべきです。

12
Xinus

本当の違いは、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によって追加される)

0
Cheney

実用的な使用法の違いは、それらがbooleansをどのように処理するかです。

TrueFalseは、pythonで10を意味する単なるキーワードです。したがって、

isinstance(True, int)

そして

isinstance(False, int)

両方ともTrueを返します。両方のブール値は整数のインスタンスです。 type()は、しかし、もっと賢いです:

type(True) == int

Falseを返します。

0
Alec Alameddine