为什么这个类变量在不同的实例中是相同的?

时间:2013-03-17 22:08:24

标签: python oop class

为什么即使在创建了一个新的类实例后我仍然保持不变?

class Test(object):
    i = 0
    def add(self):
        Test.i += 1

运行此代码

t = Test()
print t.i
t.add()
t2 = Test()
print t2.i
print t.i

给出

0
1
1

为什么t.i和t2.i都不等于0?它们不应该等于0,因为行t2 = Test()会将i重置为0吗?

3 个答案:

答案 0 :(得分:2)

i是一个类变量,而不是实例变量。它与类本身绑定(这就是为什么你可以编写Test.i,即使没有Test的实例存在)。

您必须使i成为实例变量:

class Test(object):
    def __init__(self):
        self.i = 0

    def add(self):
        self.i += 1

答案 1 :(得分:1)

您正在修改整个类的属性,而不是实例的属性。试试这个:

class Test(object):
    i = 0
    def add(self):
        self.i += 1

Python会自动将实例作为参数self传递给方法。因此,在方法中,您可以将实例的属性称为self.i

答案 2 :(得分:0)

class Test(object):
    i = 0
    def add(self):
        Test.i += 1

print "Test.i  == ",Test.i
print "'i' in dir(Test) == ",'i' in dir(Test)
print "'i' in Test.__dict__  == ",'i' in Test.__dict__

t1 = Test()
print '\n# t1 = Test() executed'
print "t1.i  == ",t1.i
print "'i' in dir(t1) == ",'i' in dir(t1)
print "'i' in t1.__dict__  == ",'i' in t1.__dict__

结果

Test.i  ==  0
'i' in dir(Test) ==  True
'i' in Test.__dict__  ==  True

# t1 = Test() executed
t1.i  ==  0
'i' in dir(t1) ==  True
'i' in t1.__dict__  ==  False

对象的名称__dict__的属性是表示此对象的名称空间的字典,也就是说它包含对象的属性。

另外,我们有:

  

DIR([对象])

     

如果对象具有名为__dir__()的方法,则将调用此方法   并且必须返回属性列表。

那么,dir(t1)如何包含属性 i t1.__dict__不包含? 所有两个dir(Test)Test.__dict__都包含属性 i

这与您回答问题的原因相同:

返回对象属性的行为很尴尬 `dir(object)反映了这种尴尬:

  

默认的dir()机制对不同类型的行为有所不同   对象,因为它试图产生最相关的,而不是   完整,信息:

     

•如果对象是模块对象,则列表包含的名称   模块的属性。
  •如果对象是类型或类对象,则   list包含其属性的名称,以及递归的   其基础的属性   •否则,列表包含对象的   属性'名称其类属性的名称,和   递归地类的基类的属性。

然后,您的问题的答案分为两部分:

1)dir(t1)给出被认为是对象的属性,但对象的真实NAMESPACE,公开为t1.__dict__不包含属性 i ,事实上,正如已经回答的那样,这是一个阶级的属性。

因此,两个实例 t1 t2 的伪属性 i 显示为等于,因为表达式t1.i和{{1事实上,评估为t2.i
Test.idir(t1)包含类的属性dir(t2)的方式相同

2)表达式Test.i如何评估为t1.i ?? 因此(构成我答案的附加信息):

  

一个类实例有一个名称实现为字典的名称空间   搜索属性引用的第一个位置。当一个   在那里找不到属性,并且实例的类有一个   通过该名称的属性,搜索继续该类   属性。

     

http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy

这意味着当在对象的命名空间中找不到属性时,会在对象是实例的类的命名空间中搜索它。