特定のオブジェクトが特定のタイプであるかどうかを確認する最良の方法は何ですか?オブジェクトが特定の型から継承するかどうかを確認してみませんか?
オブジェクトがあるとしましょうo
。それがであるstr
かどうかを確認するにはどうすればよいですか?
特定のオブジェクトが特定のタイプであるかどうかを確認する最良の方法は何ですか?オブジェクトが特定の型から継承するかどうかを確認してみませんか?
オブジェクトがあるとしましょうo
。それがであるstr
かどうかを確認するにはどうすればよいですか?
回答:
の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にはもう存在しないことに注意してください。str
bytes
または、isinstance
クラスのタプルを受け入れます。これは、返されるTrue
場合o
のいずれかの任意のサブクラスのインスタンスであります(str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
、それも本当ですisinstance(a, Object)
。ただし、場合type(a) is SubClassOfObject
は type(a) is Object == False
、しかしisinstance(a, Object) == True
。正しい?
a is b
aとbがまったく同じもの、つまりメモリ内の同じエンティティへの参照であることを意味します。したがってa
、b
サブクラスではなく、まったく同じクラスである必要がありisinstance()
ます。たとえば、stackoverflow.com / a / 133024/1072212を
ほとんどのオブジェクトの種類をチェックするPython的な方法はある...それをチェックしません。
Pythonは奨励していますのでダックタイピング、あなただけのはずですtry...except
オブジェクトのメソッドあなたがそれらを使用する方法を使用します。したがって、関数が書き込み可能なファイルオブジェクトを探している場合は、それがのサブクラスであることを確認せずにfile
、.write()
メソッドを使用してみてください。
もちろん、これらの素晴らしい抽象化が機能しなくなることが時々isinstance(obj, cls)
あります。ただし、慎重に使用してください。
if hasattr(ob, "write") and callable(ob.write):
またはいくつかのdictアクセスを保存してください...func = getattr(ob, "write", None)
if callable(func): ...
hasattr
AttributeErrorのみが抑制されます-参照:docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
返されTrue
た場合o
であるstr
かを継承するタイプのものですstr
。
type(o) is str
strのTrue
場合にのみ返されo
ます。から継承するタイプのFalse
場合に返さo
れstr
ます。
isinstance
とはtype(var) == type('')
明らかではありません。
質問が出されて回答された後、型ヒントが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の方法であり、静的タイピングの認識オーバーヘッドを課さず、冗長性が低く、すべての実行可能なタイプを受け入れ、次にいくつかのタイプを受け入れます。
mypy
使用するPythonモジュールですimportlib
。これが「静的型チェック」であるかどうかは哲学的な問題ですが、通常の言語インタープリターとインポート機構が関係しているため、ほとんどの人が予想することとは異なります。
アヒルのタイピングがいつ危険かわからずに悪である理由を以下に示します。たとえば、次は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()
class EvilDuck(Duck)
、talk()を作成してオーバーライドできます。または、おそらく、class ChineseCancerDuck(Duck)
数年後まで現れない厄介な副作用を伴います。あなたはあなたの子供を監督するだけで(そして彼女のおもちゃを徹底的にテストするのが良いでしょう:)
__file__
属性(一般的にファイルのようなオブジェクトを識別するために使用される)をオーバーライドして別の何かを意味することにより、多くのPythonコードを作成することができます。
isinstance(o, str)
Pythonのような動的言語を使用することのすばらしい点は、そのようなことをチェックする必要がないということです。
私はあなたのオブジェクトで必要なメソッドを呼び出してをキャッチするだけAttributeError
です。後でこれにより、他の(一見無関係な)オブジェクトを使用してメソッドを呼び出し、テスト用にオブジェクトをモックするなど、さまざまなタスクを実行できます。
オブジェクトのようなファイルurllib2.urlopen()
を返すWebからデータを取得するときに、これをよく使用しました。これは、実際のファイルと同じメソッドを実装しているため、ファイルから読み取るほとんどすべてのメソッドに渡すことができます。read()
しかし、私はを使用するための時間と場所があると確信していますisinstance()
。そうでなければ、おそらくそこにはありません:)
より複雑な型検証については、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)
型の__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'
ヒューゴへ:
多分list
と言うよりもarray
、おそらく型チェックの問題全体を指しています。問題のオブジェクトがリストであるかどうかを知りたくない、それが何らかのシーケンスであるかどうか、または単一のオブジェクトであるかどうかを知りたいです。したがって、シーケンスのように使用してみてください。
オブジェクトを既存のシーケンスに追加する場合、またはオブジェクトのシーケンスの場合はすべて追加する
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
これの1つのトリックは、文字列または文字列のシーケンス、あるいはその両方で作業している場合です。文字列は1つのオブジェクトと見なされることがよくありますが、文字のシーケンスでもあるため、これはトリッキーです。それは実際には単一長の文字列のシーケンスであるため、それよりも悪いです。
私は通常、単一の値またはシーケンスのみを受け入れるようにAPIを設計することを選択します。[ ]
必要に応じて、単一の値を渡すときに配置することは難しくありません。
(これはシーケンスのように見えるため、文字列でエラーが発生する可能性があります)。
最善の方法は、変数を適切に入力することです。これを行うには、「タイピング」ライブラリーを使用します。
例:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `