[Python-Dev] type(obj) vs. obj.__class__

Nick Coghlan ncoghlan at gmail.com
Tue Oct 20 05:29:45 EDT 2015


On 20 October 2015 at 10:21, Serhiy Storchaka <storchaka at gmail.com> wrote:
> On 18.10.15 00:45, Eric Snow wrote:
>>
>> So, would it make sense to establish some concrete guidelines about
>> when to use type(obj) vs. obj.__class__?  If so, what would those be?
>> It may also be helpful to enumerate use cases for "type(obj) is not
>> obj.__class__".
>
>
> My conclusion of this discussion. In Python 3 type(obj) and obj.__class__
> are the same in common case. Assigning obj.__class__ is a way to change
> type(obj). If the assignment is successful, type(obj) becomes the same as
> obj.__class__. This is used in importlib for lazy importing and some clever
> classes like the RingBuffer recipe. But __class__ assignment has many
> restrictions, and changing Python to C implementation or adding __slots__
> for sure adds new restrictions.
>
> obj.__class__ is different from type(obj) in proxy classes like weakref or
> Mock. isinstance() and pickle take __class__ to account to support proxies.
>
> Unless we write proxy class or code that should handle proxy classes, we
> shouldn't care about the difference between type(obj) and obj.__class__, and
> can use what is the more convenient. In Python this is obj.__class__ (avoids
> globals lookup), and in C this is type(obj) (much simpler and reliable
> code).

Right, this is a good summary.

Weakref proxies provide one of the simplest demonstrations of cases
where the two diverge:

>>> from weakref import proxy
>>> class C: pass
...
>>> obj = C()
>>> ref = proxy(obj)
>>> type(ref)
<class 'weakproxy'>
>>> ref.__class__
<class '__main__.C'>

When we use "obj.__class__", we're treating proxies as their target,
when we use "type(obj)", we're treating them as the proxy object.
Which of those to use depends greatly on what we're doing.

For Eric's original question that started the thread: proxy types
shouldn't inherit from a concrete container type like OrderedDict, so
type(self) and self.__class__ should *always* give the same answer,
even in subclasses.

Cheers,
Nick.

P.S. Proxy types are actually quite hard to right correctly, so if
anyone *does* need to implement one, they're likely to be best served
by starting with an existing library like wrapt:
http://wrapt.readthedocs.org/en/latest/wrappers.html

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list