Python类范围&名单

时间:2010-06-30 20:11:48

标签: python

我仍然是Python的新手,我的OO经验来自Java。所以我有一些我用Python编写的代码,对我来说非常不寻常,给出以下代码:

class MyClass():
        mylist = []
        mynum = 0

        def __init__(self):
                # populate list with some value.
                self.mylist.append("Hey!")
                # increment mynum.

                self.mynum += 1

a = MyClass()

print a.mylist
print a.mynum

b = MyClass()

print b.mylist
print b.mynum

运行此结果会产生以下输出:

['Hey!']
1
['Hey!', 'Hey!']
1

显然,我希望类变量能够产生完全相同的数据,并且输出完全相同......我无法在任何地方找到的是使列表与字符串或数字不同的原因,为什么是从后续的第一个实例中引用相同列表的列表?显然,我可能误解了某种范围机制或列表创建机制。

3 个答案:

答案 0 :(得分:8)

tlayton的答案是故事的一部分,但并不能解释所有事情。

添加

print MyClass.mynum

变得更加困惑:)。它将打印'0'。为什么?因为行

self.mynum += 1

创建实例变量,然后增加它。它不会增加 class 变量。

mylist的故事是不同的。

self.mylist.append("Hey!")

不会创建列表。它期望存在具有“追加”功能的变量。由于实例没有这样的变量,因此最终会引用类中的一个,确实存在,因为您已初始化它。就像在Java中一样,实例可以“隐式地”引用类变量。像“类字段应该由类引用,而不是由实例引用”(或类似的东西;自从我在Java中看到它以来已经有一段时间)的警告将是有序的。添加一行

print MyClass.mylist

验证这个答案:)。

简而言之:您正在初始化类变量并更新实例变量。实例可以引用类变量,但某些“更新”语句会自动为您创建实例变量。

答案 1 :(得分:5)

您在这里所做的不仅仅是创建一个类变量。在Python中,类体中定义的变量既导致类变量(“MyClass.mylist”),又导致实例变量(“a.mylist”)。这些是单独的变量,而不仅仅是单个变量的不同名称。

但是,当以这种方式初始化变量时,初始值仅计算一次并传递给每个实例的变量。这意味着,在您的代码中,MyClass的每个实例的mylist变量都引用一个列表对象。

在这种情况下,列表和数字之间的区别在于,与Java一样,当从一个变量传递到另一个变量时,会复制诸如数字之类的原始值。这会导致您看到的行为;即使变量初始化仅被计算一次,但是当将0传递给每个实例的变量时,也会复制0。但是,作为一个对象,列表没有这样的东西,所以你的append()调用都来自同一个列表。试试这个:

class MyClass():
    def __init__(self):
        self.mylist = ["Hey"]
        self.mynum = 1

这将导致每次创建实例时单独评估值。与Java不同,您不需要在此片段中附带类体声明; __init __()中的赋值作为所需的所有声明。

答案 2 :(得分:5)

我认为不同之处在于+=是一项任务(与=+相同),而append就地更改了一个对象。

    mylist = []
    mynum = 0

这会在类定义时分配一些类变量。

    self.mylist.append("Hey!")

这会通过附加字符串来更改值MyClass.mylist

    self.mynum += 1

这与self.mynum = self.mynum + 1相同,即它指定self.mynum(实例成员)。从self.mynum读取属于类成员,因为那时没有该名称的实例成员。