문제

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