Pythonで型を確認する標準的な方法は何ですか?


1278

特定のオブジェクトが特定のタイプであるかどうかを確認する最良の方法は何ですか?オブジェクトが特定の型から継承するかどうかを確認してみませんか?

オブジェクトがあるとしましょうo。それがであるstrかどうかを確認するにはどうすればよいですか?


7
まあ、Pythonの標準的なアプローチは、型をまったくチェックしないことです(デバッグしているのでない限り)。通常、それを文字列として使用しようとします(たとえば、他の文字列と連結したり、コンソールに出力したりします)。失敗すると思われる場合は、try / exceptまたはhasattrを使用してください。そうは言っても、受け入れられた答えは、Pythonの世界で一般的に「すべきでないこと」を行うための標準的な方法です。詳細については、「Pythonのダックタイピング」をGoogleやこれらをお読みください。voidspace.org.uk/python/articles/duck_typing.shtml stackoverflow.com/questions/610883/...
ジョン・クームス

9
私はクームス氏がJSON以外のシリアライズ可能なクラスのような例を見落としていると思います。大きなデータチャンクを関数(コードに影響を与えられない)を介して置く場合、そのデータの特定の部分を、たとえば渡す前に<str>に変換することができます。少なくとも、このようしてこのページに
たどり着きました

2
これを要求する最も一般的な理由は、文字列と文字列のイテラブルを区別したいということです。文字列文字列の反復可能であるため、これはトリッキーな質問です。1文字の文字列はそれ自体のシーケンスでもあります(前回チェックしたとき、おそらくこれに依存すべきではありません)。しかし、誰かが文字列のようなものを使用することはありますか?はい。それで、「文字列と他の文字列の反復可能オブジェクトを区別するにはどうすればよいですか?」正しくは:「それはあなたが何をしようとしているのかに依存します」。:-D
2016

2
Pythonの型注釈は現在のものです。mypyを
シーナ

回答:


1522

oインスタンスstrまたはのサブクラスであるかどうかを確認するには、isinstanceをstr使用します(これは「標準的な」方法です)。

if isinstance(o, str):

のタイプoが正確かどうかを確認するにはstr(サブクラスを除外):

if type(o) is str:

以下も機能し、場合によっては役立ちます。

if issubclass(type(o), str):

関連情報については、Pythonライブラリリファレンスの組み込み関数をご覧ください。

もう1つ注意:この場合、Python 2を使用している場合は、実際に次のように使用することができます。

if isinstance(o, basestring):

これはUnicode文字列もキャッチするためです(unicodeはのサブクラスではありませんstr。両方ともstrおよびのunicodeサブクラスですbasestring)。文字列()とバイナリデータ()が完全に分離さbasestringれているPython 3にはもう存在しないことに注意してください。strbytes

または、isinstanceクラスのタプルを受け入れます。これは、返されるTrue場合oのいずれかの任意のサブクラスのインスタンスであります(str, unicode)

if isinstance(o, (str, unicode)):

31
str .__ subclasses __()はstrの直接のサブクラスのみを返し、issubclass()またはisinstance()と同じことは行いません。(これを行うには、.__ subclasses __()を再帰的に呼び出す必要があります。)
Thomas Wouters

15
これは良い答えですが、Pythonでは通常これを行うべきではないという警告から始めるべきです。現状では、これは「Pythonで行うべき標準的なこと」であるという仮定を検証しているようですが、そうではありません。
Jon Coombs、2014

4
これらはpython2の回答です。たとえば、python3にはベースストリングはありません。
dfrankow 2017年

4
インスタンスと「正確に」の違いは何ですか?もしそうならtype(a) is Object、それも本当ですisinstance(a, Object)。ただし、場合type(a) is SubClassOfObjecttype(a) is Object == False、しかしisinstance(a, Object) == True。正しい?
mavavilj

1
@mavavilj- a is baとbがまったく同じもの、つまりメモリ内の同じエンティティへの参照であることを意味します。したがってabサブクラスではなく、まったく同じクラスである必要がありisinstance()ます。たとえば、stackoverflow.com / a / 133024/1072212を
Terry Brown

196

ほとんどのオブジェクトの種類をチェックするPython的な方法はある...それをチェックしません。

Pythonは奨励していますのでダックタイピング、あなただけのはずですtry...exceptオブジェクトのメソッドあなたがそれらを使用する方法を使用します。したがって、関数が書き込み可能なファイルオブジェクトを探している場合は、それがのサブクラスであることを確認せずにfile.write()メソッドを使用してみてください。

もちろん、これらの素晴らしい抽象化が機能しなくなることが時々isinstance(obj, cls)あります。ただし、慎重に使用してください。


75
私見、最もPython的な方法は、与えられた議論に対処することです。私のコードでは、オブジェクトまたはオブジェクトの配列を受け取っているかどうかがよくわからず、内部で型チェックを使用して、単一のオブジェクトを1つの要素のリストに変換しています。
サスタニン2009年

14
むしろ、その書き込みメソッドを使用しようとするだけで、例外を発生させずにこれを実行したい場合があります。この場合、あなたはそうすることができます... if hasattr(ob, "write") and callable(ob.write): またはいくつかのdictアクセスを保存してください...func = getattr(ob, "write", None) if callable(func): ...
ideasman42 '25

142
ダックタイピングとは、ライブラリを使用することです。型チェックとは、ライブラリを記述することです。同じ問題のドメインではありません。
RickyA

16
@RickyA、同意しない。ダックタイピングとは、よく知られたセマンティクスのインターフェースを使用してオブジェクトと対話することです。これは、ライブラリコードまたはそのようなライブラリを使用するコードに適用できます。
Dan Lenski 2014年

6
@ nyuszika7h、Python3ではhasattrAttributeErrorのみが抑制されます-参照:docs.python.org/3.4/library/functions.html#hasattr
ideasman42 '26

57

isinstance(o, str)返されTrueた場合oであるstrかを継承するタイプのものですstr

type(o) is strstrのTrue場合にのみ返されoます。から継承するタイプのFalse場合に返さostrます。


6
もちろん、オブジェクトが「str」のインスタンスではなく、代わりに文字列のようなものである場合、これは失敗します。unicode、mmap、UserStringまたはその他のユーザー定義型と同様。Pythonの通常のアプローチは、型チェックを行わないことです。
Thomas Wouters

6
謝る必要はありません。自分の質問に答えても大丈夫です。SOは答えのためであり、カルマではありません。
Eli Bendersky 2008

2
これは非常に役立ちます。違いますのでisinstanceとはtype(var) == type('')明らかではありません。
サスタニン2009年

30

質問が出されて回答された後、型ヒントがPythonに追加されました。Pythonの型ヒントを使用すると、型をチェックできますが、静的に型付けされた言語とは大きく異なります。Pythonの型ヒントは、期待される引数の型を、関数に関連付けられたランタイムアクセス可能なデータとして関数に関連付けます。これにより、型をチェックできます。タイプヒント構文の例:

def foo(i: int):
    return i

foo(5)
foo('oops')

この場合foo('oops')、引数の注釈付きの型はであるため、エラーをトリガーする必要がありintます。追加型ヒントはありません原因スクリプトが正常に実行されたときにエラーが発生します。ただし、他のプログラムがクエリして、タイプエラーをチェックするために使用できる予期されるタイプを説明する関数に属性を追加します。

タイプエラーを見つけるために使用できるこれらの他のプログラムの1つは次のmypyとおりです。

mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"

mypyパッケージマネージャーからインストールする必要があるかもしれません。CPythonには付属していないと思いますが、ある程度の「公式性」があるようです。)

この方法での型チェックは、静的に型付けされたコンパイル言語での型チェックとは異なります。Pythonでは型が動的であるため、実行時に型チェックを実行する必要があります。これは、たとえ正しいプログラムであっても、万が一発生すると主張した場合にはコストがかかります。明示的な型チェックは、必要以上に制限され、不必要なエラーを引き起こす可能性があります(たとえば、引数は本当に正確にlist型である必要がありますか、それとも十分に反復可能ですか?)。

明示的な型チェックの利点は、ダックタイピングよりも早くエラーをキャッチして、より明確なエラーメッセージを提供できることです。アヒルのタイプの正確な要件は、外部のドキュメントでのみ表現でき(うまくいけば完全かつ正確です)、互換性のないタイプのエラーは、発生元から遠く離れた場所で発生する可能性があります。

Pythonのタイプヒントは、タイプを指定およびチェックできる妥協案を提供することを目的としていますが、通常のコード実行中に追加のコストはかかりません。

typingパッケージの提供は、特定のタイプを必要とせずに必要な行動を表現するタイプのヒントで使用できる変数を入力します。たとえば、Iterableやなどの変数が含まれておりCallable、これらの動作を持つ任意の型の必要性を指定するヒントが含まれます。

タイプヒントはタイプをチェックするための最もPythonicな方法ですが、タイプをまったくチェックせず、ダックタイピングに依存する方がPythonicであることがよくあります。型ヒントは比較的新しいものであり、それらが最もPythonicなソリューションであるとき、陪審はまだ出ていません。比較的議論の余地はありませんが、非常に一般的な比較:タイプヒントは、強制できるドキュメントの形式を提供し、コードがより早く簡単にエラーを生成できるようにし、ダックタイピングができないエラーをキャッチし、静的にチェックできます(通常とは異なる方法で)意味はありますが、それはまだランタイム外です)。一方、ダックタイピングは長い間Pythonicの方法であり、静的タイピングの認識オーバーヘッドを課さず、冗長性が低く、すべての実行可能なタイプを受け入れ、次にいくつかのタイプを受け入れます。


2
-1:mypyは、それ自体を「静的型チェッカー」と具体的に呼んでいるため、「型チェックは実行時に実行する必要があります」のどこから取得したかわかりません。
ケビン

@Kevin振り返ってみると、これは不必要な余談でしたが、さらに理解するために、Pythonの型ヒントはランタイムデータに変換され、そのデータへのアクセスにmypy使用するPythonモジュールですimportlib。これが「静的型チェック」であるかどうかは哲学的な問題ですが、通常の言語インタープリターとインポート機構が関係しているため、ほとんどの人が予想することとは異なります。
Praxeolitic

4
それも本当ではありません。これは、使用している自体、typed_ast ASTの単なるクローンである余分な機能を持ちます。 astはモジュールをインポートしません。それらを抽象構文ツリーに解析します。
ケビン

18

アヒルのタイピングがいつ危険かわからずに悪である理由を以下に示します。たとえば、次はPythonコードです(適切なインデントが省略されている可能性があります)。isinstance関数とissubclassof関数を処理することでこの状況を回避できるので、アヒルが本当に必要なときに爆弾が発生しないようにしてください。

class Bomb:
    def __init__(self):
        ""

    def talk(self):
        self.explode()

    def explode(self):
        print "BOOM!, The bomb explodes."

class Duck:
    def __init__(self):
        ""
    def talk(self):
        print "I am a duck, I will not blow up if you ask me to talk."    

class Kid:
    kids_duck = None

    def __init__(self):
        print "Kid comes around a corner and asks you for money so he could buy a duck."

    def takeDuck(self, duck):
        self.kids_duck = duck
        print "The kid accepts the duck, and happily skips along"

    def doYourThing(self):
        print "The kid tries to get the duck to talk"
        self.kids_duck.talk()

myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()

36
型チェックを使用してもclass EvilDuck(Duck)、talk()を作成してオーバーライドできます。または、おそらく、class ChineseCancerDuck(Duck)数年後まで現れない厄介な副作用を伴います。あなたはあなたの子供を監督するだけで(そして彼女のおもちゃを徹底的にテストするのが良いでしょう:)
Brett Thomas

36
爆弾は話しません。無意味なメソッドを追加しないでください。これは起こりません。
2014年

7
@Dmitry、これはDuck Typingの一般的な批判です:en.wikipedia.org/wiki/Duck_typing#Criticism ...基本的に、言語によってセマンティクスが強制されていないインターフェースは悪だと言っています。これは、Javaのアプローチのほうが多いと思います。Pythonのダックタイピングの要点は、特定のインターフェースの意味について一般に支持されている慣習がある場合にのみ機能することです。たとえば、__file__属性(一般的にファイルのようなオブジェクトを識別するために使用される)をオーバーライドして別の何かを意味することにより、多くのPythonコードを作成することができます。
Dan Lenski

2
これはすべて古いジョーク「医者、これをやると痛い」に帰着します。...「それではそれをしないでください。」「コンパイルすれば実行する」ことに慣れている人には不満ですが、それが動的言語の世界から強迫観念をテストするようになった理由です。
2016

1
@clacke基本的に、EVERYTHINGはオブジェクトである必要があるため(文字列から可能なすべての型にマップするため)、実行時に型を厳密に強制するのはコストがかかりすぎます。通常、剛体インターフェースを使用することは非常に困難です。その上、静的言語は、動的ライブラリ、評価と文字列化、またはインターフェースを介してダックタイピングを作成する必要がある点に直面しており、これらは本質的にそれを悪にしているわけではなく、非常に強力です。
Dmitry


7

Pythonのような動的言語を使用することのすばらしい点は、そのようなことをチェックする必要がないということです。

私はあなたのオブジェクトで必要なメソッドを呼び出してをキャッチするだけAttributeErrorです。後でこれにより、他の(一見無関係な)オブジェクトを使用してメソッドを呼び出し、テスト用にオブジェクトをモックするなど、さまざまなタスクを実行できます。

オブジェクトのようなファイルurllib2.urlopen()を返すWebからデータを取得するときに、これをよく使用しました。これは、実際のファイルと同じメソッドを実装しているため、ファイルから読み取るほとんどすべてのメソッドに渡すことができます。read()

しかし、私はを使用するための時間と場所があると確信していますisinstance()。そうでなければ、おそらくそこにはありません:)


動的jsonオブジェクトを解析する場合は、これを使用する必要がある場合の良い例です。フィールドが文字列なのか辞書なのかは事前にわかりません。
灰色の

6

より複雑な型検証については、Pythonの型ヒント注釈に基づいて検証するtypeguardのアプローチが好きです

from typeguard import check_type
from typing import List

try:
    check_type('mylist', [1, 2], List[int])
except TypeError as e:
    print(e)

非常に複雑で検証を、非常にクリーンで読みやすい方法で実行できます。

check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo) 

6

型の__name__を使用して変数の型を確認できます。

例:

>>> a = [1,2,3,4]  
>>> b = 1  
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'

おかげで、これはユーザーへのフィードバックとして表示していたときに欲しかったシークレットコードです。これを見つけるのに時間がかかりすぎた...
アーロンD.マラスコ

5

ヒューゴへ:

多分listと言うよりもarray、おそらく型チェックの問題全体を指しています。問題のオブジェクトがリストであるかどうかを知りたくない、それが何らかのシーケンスであるかどうか、または単一のオブジェクトであるかどうかを知りたいです。したがって、シーケンスのように使用してみてください。

オブジェクトを既存のシーケンスに追加する場合、またはオブジェクトのシーケンスの場合はすべて追加する

try:
   my_sequence.extend(o)
except TypeError:
  my_sequence.append(o)

これの1つのトリックは、文字列または文字列のシーケンス、あるいはその両方で作業している場合です。文字列は1つのオブジェクトと見なされることがよくありますが、文字のシーケンスでもあるため、これはトリッキーです。それは実際には単一長の文字列のシーケンスであるため、それよりも悪いです。

私は通常、単一の値またはシーケンスのみを受け入れるようにAPIを設計することを選択します。[ ]必要に応じて、単一の値を渡すときに配置することは難しくありません。

(これはシーケンスのように見えるため、文字列でエラーが発生する可能性があります)。


0

タイプをチェックする簡単な方法は、タイプを知っているものと比較することです。

>>> a  = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True


-7

以下の行で、指定した値がどの文字タイプであるかを確認できます。

def chr_type(chrx):
    if chrx.isalpha()==True:
        return 'alpha'
    elif chrx.isdigit()==True:
        return 'numeric'
    else:
        return 'nothing'

chr_type("12)

3
この回答@Venkatesanを削除してもよろしいですか?
グレイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.