2014-09-30 140 views
0

我需要编写代码的帮助,这些代码完成我认为应该完成的任务。实例和类变量

下面的代码:

class Food: 
    kind = 'fruit' 
    def __init__(self, name): 
     self.name = name 

a = Food('tomato') 
b = Food('cabbage') 

print 'a ->', a.kind 
print 'b ->', b.kind 
print 'change a\'s kind' 
a.kind = 'veg' 
print 'a ->', a.kind 
print 'b ->',b.kind 
print 'change kind in the class' 
Food.kind = 'meat' 
print 'a ->', a.kind 
print 'b ->', b.kind 

我得到的输出是这样的:

a -> fruit 
b -> fruit 
change a's kind 
a -> veg 
b -> fruit 
change kind in the class 
a -> veg 
b -> meat 

这是困扰我的最后一个结果。如果我已经将'kind'正确地声明为class属性,那么肯定当我在'Food.kind ='类中改变它时,它应该改变它的两个实例。实际上,当我通过其中一个实例赋予它新的价值时,我预期它会改变,但它只是将它改变为一个。我在这里错过了什么?

+1

检查下一个环节:http://www.toptal.com/python/python-class-attributes-an-overly-彻底指导。它解释了类属性和实例属性如何在Python中工作。 – mvillaress 2014-09-30 21:46:21

+0

在分配'a.kind ='veg''之前,'kind'属性在实例中不存在,并且引用类变量。如果你想让它重新返回到类变量,那么'del a.kind',你将再次获得'meat'。 – sberry 2014-09-30 21:53:38

回答

0

您可能已经意识到,在C++/Java中通过实例引用静态成员是被忽视的。相反,我们鼓励你通过类引用在Java中引用静态成员,例如:

theThing.value = 1; // bad 
Thing.value = 1; // good 

在Python中,在一个实例读取字段时,Python会先看看实例的领域。如果没有找到实例字段,则会检查实例的类的字段。

写入字段时,写入的字段为总是被引用的对象 - 是一个实例或类。例如:

theThing.value = 1 # creates an instance field if one does not exist 
Thing.value = 1 # creates a class field if one does not exist 

因此,读取的kind值时:a.kind总是读实例字段(除非该字段被删除);和b.kind将始终读取类字段(除非创建实例字段)。

1

属性查找从实例词典开始,因此在类中更改kind不会影响* akind属性。但是,如果在Food中找不到该类的其他实例,仍然没有该属性,它仍然会在类字典中查找它,或者在类树中进一步查找它。

>>> a.kind = 'veg' 
>>> a.__dict__ 
{'kind': 'veg', 'name': 'tomato'} 
>>> b.__dict__ 
{'name': 'cabbage'} 

,因为没有基类属性在这里查找将Food为导致AttributeError不存在的属性后立即停止。

>>> a.foo 

Traceback (most recent call last): 
    File "<pyshell#6>", line 1, in <module> 
    a.foo 
AttributeError: Food instance has no attribute 'foo' 

注意,在新式的类special methods不在课堂实例总是抬头。但是由于您使用的是老式类(在Python 3中删除),情况并非如此。但建议始终使用新类(即继承自Python 2中的object)。

你应该阅读:New-style and classic classes.


* 可变类属性(列表,字典等)都在这里有一个例外,从实例或类对他们做就地操作将无处不在课堂上体现而其他情况下(除非一个实例定义同名新属性):

class Food: 
    kind = [] 
    def __init__(self, name): 
     self.name = name 

a = Food('tomato') 
b = Food('cabbage') 
b.kind = [] 
a.kind.append(10) 
Food.kind.append(20) 
print a.kind #[10, 20] 
print b.kind #[] b.kind points to a different object due to the assignment above 
print Food.kind #[10, 20]