2013-12-23 251 views
3

這段代碼應該打印什麼?Python瘋狂易變

class Parent(): 
    class Meta(object): 
     classattr = "Hello" 

class Child(Parent): 
    pass 


Child.Meta.classattr = "world" 


ch = Child() 
pr = Parent() 

ch.Meta.classattr = "Oppa" 

print Parent.Meta.classattr 
print Child.Meta.classattr 

print pr.Meta.classattr 
print ch.Meta.classattr 

我希望以下內容:

Hello 
world 
Hello 
Oppa 

,但得到

Oppa 
Oppa 
Oppa 
Oppa 

所以......我可以通過修改子類的實例修改父類(不是實例!)。這是正常的嗎?

回答

6

Child.Meta實際上Parent.Meta - 類Child沒有自己的Meta類屬性,這樣屬性的查找規則解析爲Parent.Meta。此外,因爲它是一個類屬性,所以對Parent(包括Child的實例)的實例的任何查找都將解析爲完全相同的類對象。

+2

通過運行'ch.Meta是pr.Meta'可以很容易驗證。 –

+0

好了,但我已經tryed使用deepcopy的,並沒有什麼改變: '進口副本 父類(對象): 類IntClass: intclassattr = 「你好」] 兒童= copy.deepcopy(家長) Child.IntClass.intclassattr.append( 「世界」) 打印Parent.IntClass.intclassattr' 結果是 '[ '你好', '世界']' 但deepcopy的必須複製對象的所有字段遞歸地,我如何從Parent繼承並更改類字段,而不必在Parent實例中更改它es? – Makc

+1

來自'copy'模塊的文檔:「此版本不復制類似模塊,類,函數,方法(...)」。你可以在'Child = copy.deepcopy(Parent)'後查看,'Child is Parent'是真的。 –

1

我會盡力解釋這裏發生了什麼:

class Parent(): 
    class Meta(object): 
     classattr = "Hello" 

class Child(Parent): 
    pass 


Child.Meta.classattr = "world" 

在這裏,你要分配的「世界」到元的classattr。 Meta最初是在Parent內部定義的並不重要;孩子和家長分享相同Meta

ch = Child() 
pr = Parent() 

ch.Meta.classattr = "Oppa" 

在這裏,您將分配「世界」到Meta的classattrch是否是一個實例並不重要。 Meta始終是同一個對象。

print Parent.Meta.classattr 
print Child.Meta.classattr 

print pr.Meta.classattr 
print ch.Meta.classattr 

在這裏,您打印的相同元的classattr

0

我認爲最簡單的解釋是,元類只是一個普通的對象(類型type)由Parent引用,子類和實例不要複製的元類,但只需要創建一個新的引用它(或者實際上嚴格地說甚至沒有 - 只是屬性查找的工作原理)。因此,無論何時您將新值存儲到classattr中,實際上都是修改同一對象的相同屬性。