2013-12-23 157 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中,实际上都是修改同一对象的相同属性。