Python type() or __class__, == or is
Solution 1:
For old-style classes, there is a difference:
>>> 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'>
The point of new-style classes was to unify class and type. Technically speaking, __class__
is the only solution that will work both for new and old-style class instances, but it will also throw an exception on old-style class objects themselves. You can call type()
on any object, but not every object has __class__
. Also, you can muck with __class__
in a way you can't muck with type()
.
>>> class Z(object):
... def __getattribute__(self, name):
... return "ham"
...
>>> z = Z()
>>> z.__class__
'ham'
>>> type(z)
<class '__main__.Z'>
Personally, I usually have an environment with new-style classes only, and as a matter of style prefer to use type()
as I generally prefer built-in functions when they exist to using magic attributes. For example, I would also prefer bool(x)
to x.__nonzero__()
.
Solution 2:
The result of type()
is equivalent to obj.__class__
in new style classes, and class objects are not safe for comparison using is
, use ==
instead.
For new style classes the preferable way here would be type(obj) == Foo
.
As Michael Hoffman pointed out in his answer, there is a difference here between new and old style classes, so for backwards compatible code you may need to use obj.__class__ == Foo
.
For those claiming that isinstance(obj, Foo)
is preferable, consider the following scenario:
class Foo(object):
pass
class Bar(Foo):
pass
>>> obj = Bar()
>>> isinstance(obj, Foo)
True
>>> type(obj) == Foo
False
The OP wants the behavior of type(obj) == Foo
, where it will be false even though Foo
is a base class of Bar
.
Solution 3:
is
should only be used for identity checks, not type checks (there is an exception to the rule where you can and should use is
for check against singletons).
Note: I would generally not use type
and ==
for type checks, either. The preferable way for type checks is isinstance(obj, Foo)
. If you ever have a reason to check if something is not an subclass instance, it smells like a fishy design to me. When class Foo(Bar):
, then Bar
is a Foo
, and you should be avoiding any situations where some part of your code has to work on a Foo
instance but breaks on a Bar
instance.