オブジェクトがクラスのインスタンスであり、このクラスのみ(サブクラスではない)かどうかをテストしたいと思います。私はそれを次のいずれかで行うことができます:
_obj.__class__ == Foo
obj.__class__ is Foo
type(obj) == Foo
type(obj) is Foo
_
別のものを選択する理由はありますか? (パフォーマンスの違い、落とし穴など)
言い換えると、a)___class__
_とtype(x)
の使用の間に実際的な違いはありますか? b)クラスオブジェクトはis
を使用して比較しても常に安全ですか?
更新:フィードバックをありがとう。クラスオブジェクトがシングルトンであるかどうかにはまだ戸惑っていますが、常識ではそうですが、確認を得るのは非常に困難です(「python」、「class」、「unique」、または「singleton」をグーグルで試してください)。 。
また、特定のニーズに対しては、機能する「安価な」ソリューションが最適であることを明確にしたいと思います。 Python=を削除して、その特定のモジュールをCで開発する)ことですが、質問の背後にある理由は、言語の理解を深めることでした。そのため、___class__ is
_に落ち着くのではなく、少し議論を延ばして、経験豊富な人々の意見を聞くことができます。これまでのところ、非常に実り多いものです!
小さなテストを実行して、4つの代替案のパフォーマンスをベンチマークしました。プロファイラーの結果は次のとおりです。
_ Python PyPy (4x)
type() is 2.138 2.594
__class__ is 2.185 2.437
type() == 2.213 2.625
__class__ == 2.271 2.453
_
当然のことながら、is
はすべてのケースで_==
_よりも優れたパフォーマンスを示しました。 type()
は、Python(2%高速)および___class__
_の方がPyPyで高速(6%高速)にパフォーマンスが向上しました。興味深いことに___class__ ==
_ PyPyでのパフォーマンスはtype() is
よりも優れています。
pdate 2:「クラスはシングルトン」の意味を理解していない人が多いので、例を挙げて説明します。
_>>> class Foo(object): pass
...
>>> X = Foo
>>> class Foo(object): pass
...
>>> X == Foo
False
>>> isinstance(X(), Foo)
False
>>> isinstance(Foo(), X)
False
>>> x = type('Foo', (object,), dict())
>>> y = type('Foo', (object,), dict())
>>> x == y
False
>>> isinstance(x(), y)
False
>>> y = copy.copy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
>>> y = copy.deepcopy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
_
type
型のN個のオブジェクトが存在するかどうかは関係ありません。オブジェクトが与えられた場合、1つだけがそのクラスになります。この場合、参照のために比較しても安全です。また、参照比較は常に値比較より安くなるため、上記の主張が成り立つかどうかを知りたいと思いました。誰かが反対の証拠を提示しない限り、私はそれがそうであるという結論に達しています。
古いスタイルのクラスの場合、違いがあります。
_>>> class X: pass
...
>>> type(X)
<type 'classobj'>
>>> X.__class__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class X has no attribute '__class__'
>>> x = X()
>>> x.__class__
<class __main__.X at 0x171b5d50>
>>> type(x)
<type 'instance'>
_
新しいスタイルのクラスのポイントは、クラスとタイプを統一することでした。技術的には、___class__
_は、新しいスタイルのクラスインスタンスと古いスタイルのクラスインスタンスの両方で機能する唯一のソリューションですが、古いスタイルのクラスオブジェクト自体にも例外をスローします。どのオブジェクトでもtype()
を呼び出すことができますが、すべてのオブジェクトが___class__
_を持っているわけではありません。また、type()
でマックできない方法で___class__
_でマックできます。
_>>> class Z(object):
... def __getattribute__(self, name):
... return "ham"
...
>>> z = Z()
>>> z.__class__
'ham'
>>> type(z)
<class '__main__.Z'>
_
個人的には、私は通常、新しいスタイルのクラスのみを使用する環境を持っています。スタイルの問題として、マジック属性を使用するよりも組み込み関数が存在する場合、通常は組み込み関数を好むため、type()
を使用することを好みます。たとえば、私はbool(x)
よりもx.__nonzero__()
を優先します。
type()
の結果は、新しいスタイルクラスの_obj.__class__
_と同等であり、クラスオブジェクトはis
を使用した比較には安全ではありません。代わりに_==
_を使用してください。
新しいスタイルクラスの場合ここでの望ましい方法はtype(obj) == Foo
です。
Michael Hoffmanが彼の答えで指摘したように、ここでは新しいスタイルのクラスと古いスタイルのクラスに違いがあるため、下位互換性のあるコードでは_obj.__class__ == Foo
_を使用する必要がある場合があります。
isinstance(obj, Foo)
が望ましいと主張する人は、次のシナリオを検討してください。
_class Foo(object):
pass
class Bar(Foo):
pass
>>> obj = Bar()
>>> isinstance(obj, Foo)
True
>>> type(obj) == Foo
False
_
OPは、Foo
がBar
の基本クラスであってもfalseになるtype(obj) == Foo
の動作を望んでいます。
is
は、タイプチェックではなく、IDチェックにのみ使用する必要があります(シングルトンに対するチェックにis
を使用でき、また使用する必要があるルールには例外があります)。
注:通常、型チェックにもtype
と_==
_は使用しません。型チェックの望ましい方法はisinstance(obj, Foo)
です。何かがサブクラスインスタンスではないかどうかを確認する理由がある場合、それは私には魚のようなデザインのようなにおいがします。 class Foo(Bar):
の場合、Bar
is aFoo
であり、コードの一部が処理する必要がある状況を回避する必要がありますFoo
インスタンスですが、Bar
インスタンスで中断します。