I want to test whether an object is an instance of a class, and only this class (no subclasses). I could do it either with:
obj.__class__ == Foo
obj.__class__ is Foo
type(obj) == Foo
type(obj) is Foo
Are there reasons to choose one over another? (performance differences, pitfalls, etc)
In other words: a) is there any practical difference between using __class__
and type(x)
? b) are class objects always safe for comparison using is
?
Update: Thanks all for the feedback. I'm still puzzled by whether or not class objects are singletons, my common sense says they are, but it's been really hard to get a confirmation (try googling for "python", "class" and "unique" or "singleton").
I'd also like to clarify that, for my particular needs, the "cheaper" solution that just works is the best, since I'm trying to optimize the most out of a few, specialized classes (almost reaching the point where the sensible thing to do is to drop Python and develop that particular module in C). But the reason behind the question was to understand better the language, since some of its features are a bit too obscure for me to find that information easily. That's why I'm letting the discussion extend a little instead of settling for __class__ is
, so I can hear the opinion of more experienced people. So far it's been very fruitful!
I ran a small test to benchmark the performance of the 4 alternatives. The profiler results were:
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
Unsurprisingly, is
performed better than ==
for all cases. type()
performed better in Python (2% faster) and __class__
performed better in PyPy (6% faster). Interesting to note that __class__ ==
performed better in PyPy than type() is
.
Update 2: many people don't seem to understand what I mean with "a class is a singleton", so I'll ilustrate with an example:
>>> 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
It doesn't matter if there are N objects of type type
, given an object, only one will be its class, hence it's safe to compare for reference in this case. And since reference comparison will always be cheaper than value comparison, I wanted to know whether or not my assertion above holds. I'm reaching the conclusion that it does, unless someone presents evidence in contrary.
I can confirm that
__instance__
is a singleton. Here is the proof.As you can see both
t1
andt2
print out the same value in memory even thought1
andt2
are at different values in memory. Here is the proof of that.The
__instance__
method only exists if you usedclass "name"(object):
. If you use the classic style class,class "name":
, than the__instance__
method doesn't exist.What this means is to be the most generic you probably want to use
type
unless you know for a fact instance does exist.For old-style classes, there is a difference:
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 calltype()
on any object, but not every object has__class__
. Also, you can muck with__class__
in a way you can't muck withtype()
.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 preferbool(x)
tox.__nonzero__()
.is
should only be used for identity checks, not type checks (there is an exception to the rule where you can and should useis
for check against singletons).Note: I would generally not use
type
and==
for type checks, either. The preferable way for type checks isisinstance(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. Whenclass Foo(Bar):
, thenBar
is aFoo
, and you should be avoiding any situations where some part of your code has to work on aFoo
instance but breaks on aBar
instance.The result of
type()
is equivalent toobj.__class__
in new style classes, and class objects are not safe for comparison usingis
, 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:The OP wants the behavior of
type(obj) == Foo
, where it will be false even thoughFoo
is a base class ofBar
.