Вопрос

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top