类型与弱引用的行为 - 无法理解

3 投票
1 回答
577 浏览
提问于 2025-04-17 20:16

我一直认为在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 个回答

4

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 的相等性。

撰写回答