2013-03-25 45 views
3

我一直認爲在Python解釋器值x.__class__type(x)是等效的。但是,如果我們做到以下幾點(在Python 2.7,3.3和也PyPy 2.0b1):類型的行爲與weakref - 不明白

>>> 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只是取代了僞裝的屬性)。即使isinstancey標識爲set

但是type顯示「真」類型 - weakproxy。因此,type不使用__class__屬性來標識參數的類型,是嗎?它是否爲此目的使用了一些「更可靠」的來源?如果是這樣,我們可以直接訪問它嗎?

回答

4

x.__class__type(x)不等價。 type(x)紮根於typeobject.c,並將返回真實類型ob_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的等式。

+0

謝謝你的回答。 關於'isinstance'。它是否首先檢查'ob_type',然後如果它不等於'__class__'? – 2013-03-26 09:06:49

+1

@IvanYurchenko,粗略地說,是的,先是'ob_type',然後是'__class__'。實際上,它們之間有一個特殊的鉤子['__instancecheck__'](http://docs.python.org/2/reference/datamodel.html?highlight=__instancecheck__#class.__instancecheck__)。 – nymk 2013-03-26 09:43:41

+0

謝謝@nymk。 – 2013-03-26 10:55:57