web-dev-qa-db-ja.com

Python type()または__class__、==または

オブジェクトがクラスのインスタンスであり、このクラスのみ(サブクラスではない)かどうかをテストしたいと思います。私はそれを次のいずれかで行うことができます:

_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つだけがそのクラスになります。この場合、参照のために比較しても安全です。また、参照比較は常に値比較より安くなるため、上記の主張が成り立つかどうかを知りたいと思いました。誰かが反対の証拠を提示しない限り、私はそれがそうであるという結論に達しています。

52
mgibsonbr

古いスタイルのクラスの場合、違いがあります。

_>>> 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__()を優先します。

29
Michael Hoffman

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は、FooBarの基本クラスであってもfalseになるtype(obj) == Fooの動作を望んでいます。

12
Andrew Clark

isは、タイプチェックではなく、IDチェックにのみ使用する必要があります(シングルトンに対するチェックにisを使用でき、また使用する必要があるルールには例外があります)。

注:通常、型チェックにもtypeと_==_は使用しません。型チェックの望ましい方法はisinstance(obj, Foo)です。何かがサブクラスインスタンスではないかどうかを確認する理由がある場合、それは私には魚のようなデザインのようなにおいがします。 class Foo(Bar):の場合、Baris aFooであり、コードの一部が処理する必要がある状況を回避する必要がありますFooインスタンスですが、Barインスタンスで中断します。

12
wim