質問
特定のオブジェクトが特定のタイプであるかどうかを確認する最良の方法は何ですか?オブジェクトが特定の型を継承しているかどうかを確認する方法はどうですか?
オブジェクト o
があるとします。 str
かどうかを確認するにはどうすればよいですか?
解決
o
が str
のインスタンスまたは str
のサブクラスであるかどうかを確認するには、 isinstance (これは" canonical"の方法です):
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にはもう存在しないことに注意してください。文字列の厳密な分離( str
)およびバイナリデータ( bytes
)。
あるいは、 isinstance
はクラスのタプルを受け入れます。 xが(str、unicode)のいずれかのサブクラスのインスタンスである場合、これはTrueを返します。
if isinstance(o, (str, unicode)):
他のヒント
オブジェクトのタイプをチェックする most Pythonの方法は...チェックしないことです。
Pythonは Duck Typing を推奨しているため、 try ... except
使用したい方法でオブジェクトのメソッドを使用します。関数が書き込み可能なファイルオブジェクトを探している場合、それが file
のサブクラスであることをチェックしない、その .write()
メソッド!
もちろん、時にはこれらの素晴らしい抽象化が壊れて、必要なのは isinstance(obj、cls)
です。ただし、控えめに使用してください。
o
が str
またはタイプの場合、 isinstance(o、str)
は True
を返します str
を継承しています。
o
がstrである場合にのみ、 type(o)is str
は True
を返します。 o
が str
を継承するタイプの場合、 False
を返します。
質問への回答が行われた後、 Pythonにタイプヒントが追加されました。 Pythonの型ヒントを使用すると、型をチェックできますが、静的に型付けされた言語とは非常に異なる方法でチェックできます。 Pythonのタイプヒントは、関数に関連付けられた実行時アクセス可能データとして、期待される引数のタイプを関数に関連付けます。これにより、チェック対象のタイプを許可できます。型ヒントの構文の例:
def foo(i: int):
return i
foo(5)
foo('oops')
この場合、注釈の引数の型は int
であるため、 foo( 'oops')
に対してエラーをトリガーする必要があります。追加されたタイプヒントは、スクリプトが正常に実行されたときにエラーが発生することはありません 。ただし、他のプログラムがタイプエラーをチェックするためにクエリおよび使用できる予想されるタイプを記述する属性を関数に追加します。
型エラーを見つけるために使用できるこれらの他のプログラムの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
などの変数が含まれており、これらの動作を持つ型の必要性を指定します。
型のヒントは型をチェックするための最もPython的な方法ですが、型をまったくチェックせず、アヒルの型付けに依存することは、多くの場合Python的なものです。型のヒントは比較的新しく、それらが最もPythonicなソリューションであるとき、審査員はまだ出ています。比較的議論の余地のないが非常に一般的な比較:型のヒントは、強制できるドキュメントの形式を提供し、コードがより早くより理解しやすいエラーを生成できるようにし、ダックタイピングでは不可能なエラーをキャッチでき、静的にチェックできます(異常な場合)センスですが、それはまだランタイム外です)。一方、アヒルの型付けは長い間Pythonの方法であり、静的型付けの認知オーバーヘッドを課すことはなく、冗長性が低く、すべての実行可能な型を受け入れます。
これは、アヒルのタイピングが危険なときを知らずに悪である理由の例です。 たとえば、次の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()
isinstance(o, str)
Pythonのような動的言語を使用することの素晴らしい点は、そのようなものをチェックする必要がないことです。
オブジェクトで必要なメソッドを呼び出して、 AttributeError
をキャッチします。後でこれにより、他の(一見無関係な)オブジェクトを使用してメソッドを呼び出して、テスト用にオブジェクトをモックするなど、さまざまなタスクを実行できます。
file like オブジェクトを返す urllib2.urlopen()
を使用してWebからデータを取得するときに、これを頻繁に使用しました。これは、実際のファイルと同じ read()
メソッドを実装するため、ファイルから読み取るほとんどすべてのメソッドに渡すことができます。
しかし、 isinstance()
を使用するための時間と場所があると確信しています。そうでなければ、おそらく存在しません:)
ヒューゴへ:
おそらく array
ではなく list
を意味しますが、それは型チェックの問題全体を指し示しています-問題のオブジェクトがリストでは、それが何らかの種類のシーケンスであるか、単一のオブジェクトであるかを知りたいと思います。シーケンスのように使用してみてください。
既存のシーケンスにオブジェクトを追加する場合、またはオブジェクトのシーケンスである場合はすべて追加する
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
これの1つの秘isは、文字列および/または文字列のシーケンスを操作している場合です。それよりも悪いのは、それが実際に単一長の文字列のシーケンスだからです。
通常、単一の値またはシーケンスのみを受け入れるようにAPIを設計することを選択します。必要に応じて渡すときに、単一の値を []
で囲むのは難しくありません。
(これは文字列でエラーを引き起こす可能性がありますが、文字列はシーケンスのように見えます。)
より複雑な型検証のために、私は typeguard のPython型ヒント注釈に基づく検証のアプローチが好きです:
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)
次の行で、指定された値がどの文字タイプであるかを確認できます。
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)