类型与弱引用的行为 - 无法理解
我一直认为在Python解释器中,x.__class__
和type(x)
是一样的。但是如果我们在Python 2.7、3.3和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'>)
我们会发现y.__class__
对应的是weakref.proxy
的包装类型(我猜weakref.proxy
只是为了伪装而替换了这个属性)。甚至isinstance
也把y
识别为set
类型。
但是type
显示的是“真实”的类型——weakproxy
。所以,type
并不是通过__class__
属性来识别一个对象的类型,对吧?它是不是用了一些“更可靠”的来源来做这个?如果是这样,我们能直接访问这个来源吗?
1 个回答
x.__class__
和 type(x)
其实是不同的东西。type(x)
是在一个叫做 typeobject.c 的地方定义的,它会返回真正的类型 ob_type
。
/* 特殊情况:type(x) 应该返回 x->ob_type */
而 x.__class__
只是查找一个属性。它等同于 object.__getattribute__(x, '__class__')
,除非这个属性查找被重新定义了。
object
的 '__class__'
是一个数据描述符,这个描述符也是在 typeobject.c 中定义的。它的 getter 也会返回 ob_type
。所以在大多数情况下,x.__class__
和 type(x)
返回的结果是一样的。
但是 weakproxy
,也就是 _PyWeakref_ProxyType
,故意定义了自己的 proxy_getattr
。这就是为什么在你的例子中,y.__class__
和 type(y)
不一样的原因。
在下面的实验中,我们可以实现相同的效果。
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'>
此外,在这个例子中,isinstance(c, A)
和 isinstance(c, C)
都是对的。因为 isinstance
会先检查 ob_type
的相等性。