2011-02-02 41 views
55
>>> class A(object): pass 
... 
>>> A.__dict__ 
<dictproxy object at 0x173ef30> 
>>> A.__dict__.__dict__ 
Traceback (most recent call last): 
    File "<string>", line 1, in <fragment> 
AttributeError: 'dictproxy' object has no attribute '__dict__' 
>>> A.__dict__.copy() 
{'__dict__': <attribute '__dict__' of 'A' objects> ... } 
>>> A.__dict__['__dict__'] 
<attribute '__dict__' of 'A' objects> # What is this object? 

如果我做A.something = 10,則進入A.__dict__。什麼這個<attribute '__dict__' of 'A' objects>發現在A.__dict__.__dict__,它什麼時候包含什麼?什麼是Python類的__dict __.__ dict__屬性?

+6

一個更合適的示例變量可能已經``ive`。至少它會讓這個問題變得更「A .__ dict __ ['ive']`);我會看到自己出來 – Joakim 2015-10-01 15:01:49

回答

77

所有A.__dict__.__dict__首先是從A.__dict__['__dict__']不同,前者不存在。後者是類的實例將具有的__dict__屬性。它是一個描述符對象,它返回特定實例的內部屬性字典。簡而言之,對象的__dict__屬性不能存儲在對象的__dict__中,因此它通過類中定義的描述符進行訪問。

要理解這一點,您必須閱讀documentation of the descriptor protocol

短的版本:

  1. 對於A類,由A.__dict__['__dict__']提供訪問instance.__dict__的一個實例,其是相同的vars(A)['__dict__']
  2. 對於A類,訪問A.__dict__type.__dict__['__dict__'](理論上)提供,其與vars(type)['__dict__']相同。

長版本:

兩個類和對象同時提供通過屬性操作者(通過類或元類的__getattribute__實現)訪問屬性,並且__dict__屬性/協議,該協議被用來通過vars(ob)

對於普通的對象,則__dict__對象創建一個單獨的dict對象,它存儲的屬性,並__getattribute__首先嚐試訪問,並從那裏得到的屬性(試圖利用描述符來尋找類的屬性之前協議,並在致電__getattr__之前)。類上的__dict__描述符實現對此字典的訪問。

  • x.name等同於審判那些依次爲:x.__dict__['name']type(x).name.__get__(x, type(x))type(x).name
  • x.__dict__不相同,但跳過第一個原因是顯而易見的

至於它的instance__dict__來是不可能的存儲在實例的__dict__中,而是直接通過描述符協議訪問,並存儲在實例中的特殊字段中。

雖然他們的__dict__是一個假裝爲字典(但可能不是內部)的特殊代理對象,但它不允許您更改它或將其替換爲另一個類,但類的情況也適用。此代理允許您在其他所有情況下訪問特定於其的類的屬性,而不是在其一個基礎中定義的屬性。

默認情況下,一個空類的vars(cls)承載三個描述符 - 用於__dict__存儲由weakref內部使用的情況下,__weakref__的屬性和類的文檔字符串。如果您定義了__slots__,前兩個可能會消失。然後,您將不具有__dict____weakref__屬性,但相反,您將爲每個插槽擁有單個類屬性。然後,實例的屬性將不會存儲在字典中,並且將通過類中的相應描述符提供對它們的訪問。


最後,該不一致性A.__dict__A.__dict__['__dict__']不同是因爲屬性__dict__,通過例外,從未vars(A)擡起頭,所以什麼是真的不適合幾乎任何其他真你會使用的屬性。例如,A.__weakref__A.__dict__['__weakref__']是相同的。如果這種不一致性不存在,則使用A.__dict__將不起作用,您必須始終使用vars(A)來代替。

+5

感謝您的詳細解答。儘管我不得不多次閱讀它,但我認爲自從我學習了很多關於Python的新細節以來已經有一段時間了。 – porgarmingduod 2011-02-03 12:52:58

7

由於A.__dict__是存儲A屬性的字典,A.__dict__['__dict__']是直接引用同一A.__dict__屬性。

A.__dict__包含對其自身的(種類)引用。 「kind-of」部分是爲什麼表達式A.__dict__返回dictproxy而不是正常的dict

>>> class B(object): 
...  "Documentation of B class" 
...  pass 
... 
>>> B.__doc__ 
'Documentation of B class' 
>>> B.__dict__ 
<dictproxy object at 0x00B83590> 
>>> B.__dict__['__doc__'] 
'Documentation of B class' 
+5

`A .__ dict __ ['__ dict __']`不是對`A .__ dict__ `。它實現了實例的`__dict__`屬性。 (A(),A)`返回A()`的屬性,而'A .__ dict __ ['__ dict __'] .__ get __(A,類型)`失敗。 – 2011-02-02 17:37:21

5

讓我們做一些探索!

>>> A.__dict__['__dict__'] 
<attribute '__dict__' of 'A' objects> 

我想知道那是什麼?

>>> type(A.__dict__['__dict__']) 
<type 'getset_descriptor'> 

getset_descriptor對象有什麼屬性?

>>> type(A.__dict__["__dict__"]).__dict__ 
<dictproxy object at 0xb7efc4ac> 

只要製作dictproxy的副本,我們可以發現一些有趣的特性,特別是__objclass____name__

>>> A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__ 
(<class '__main__.A'>, '__dict__') 

所以__objclass__A__name__參考也許是一個屬性的只是字符串'__dict__',叫什麼名字?

>>> getattr(A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__) == A.__dict__ 
True 

在那裏,我們有它! A.__dict__['__dict__']是可以引用回A.__dict__的對象。

+0

PEP 252表示`__objclass__`是_defined_這個屬性的類,並不是那個類的屬性。這使得你的`getattr`示例不正確。更正確的是`getattr(A().__ dict __ ['__ dict __'] .__ objclass__,A .__ dict __ ['__ dict __'] .__ name __)` – 2011-02-02 17:48:56

4

你可以試試下面這個簡單的例子來了解更多的這一點:

>>> class A(object): pass 
... 
>>> a = A() 
>>> type(A) 
<type 'type'> 
>>> type(a) 
<class '__main__.A'> 
>>> type(a.__dict__) 
<type 'dict'> 
>>> type(A.__dict__) 
<type 'dictproxy'> 
>>> type(type.__dict__) 
<type 'dictproxy'> 
>>> type(A.__dict__['__dict__']) 
<type 'getset_descriptor'> 
>>> type(type.__dict__['__dict__']) 
<type 'getset_descriptor'> 
>>> a.__dict__ == A.__dict__['__dict__'].__get__(a) 
True 
>>> A.__dict__ == type.__dict__['__dict__'].__get__(A) 
True 
>>> a.__dict__ == type.__dict__['__dict__'].__get__(A)['__dict__'].__get__(a) 
True 

從上面的例子,似乎類對象的屬性按其類存儲類的屬性按其類,存儲其是元類。這也通過以下驗證:

>>> a.__dict__ == A.__getattribute__(a, '__dict__') 
True 
>>> A.__dict__ == type.__getattribute__(A, '__dict__') 
True