I always believed that in Python interpreter values of x.__class__ and type(x) are equivalent. But if we do the following (in Python 2.7, 3.3 and also PyPy 2.0b1):
>>> import weakref
>>> x = set()
>>> y = weakref.proxy(x)
>>> x.__class__, isinstance(x, set), type(x)
(<type 'set'>, True, <type 'set'>)
>>> y.__class__, isinstance(y, set), type(y)
(<type 'set'>, True, <type 'weakproxy'>)
we'll see that y.__class__ corresponds to the wrapped type for weakref.proxy (I suppose that weakref.proxy just replaces the attribute for disguise). Even isinstance identifies y as set.
But type shows the "true" type -- weakproxy. So, type doesn't use __class__ attribute to identify an argument's type, does it? Does it use some "more reliable" source for this purpose? If so, can we access it directly?
x.__class__ and type(x) are not equivalent.
type(x) is rooted in typeobject.c, and will return the true type ob_type.
/* Special case: type(x) should return x->ob_type */
While x.__class__ is just an attribute lookup. It is equivalent to object.__getattribute__(x, '__class__'), unless the attribute lookup has been redefined.
object's '__class__' is a data descriptor, which is also defined in typeobject.c. Its getter returns ob_type as well. Thus, in most cases, x.__class__ and type(x) return the same thing.
But weakproxy, namely _PyWeakref_ProxyType, deliberately defined its own proxy_getattr. That's why y.__class__ is not the same as type(y) in your case.
In the following experiment, we can achieve the same effect.
class A(object):
pass
class C(object):
def __getattribute__(self, name):
if name == '__class__':
return A
return object.__getattribute__(self, name)
>>> c = C()
>>> c.__class__
<class '__main__.A'>
>>> type(c)
<class '__main__.C'>
Moreover, isinstance(c, A) and isinstance(c, C) are both true in this example. Since isinstance would check the equality of ob_type first.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With