关于类变量:python oop和list

Python OOP and lists

我对python不熟悉,它是OOP的东西,不能让它工作。以下是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Tree:

    root = None;
    data = [];

    def __init__(self, equation):
        self.root = equation;

    def appendLeft(self, data):
        self.data.insert(0, data);

    def appendRight(self, data):
        self.data.append(data);

    def calculateLeft(self):
        result = [];
        for item in (self.getLeft()):
            if (type(item) == type(self)):
                data = item.calculateLeft();
            else:
                data = item;
            result.append(item);
        return result;

    def getLeft(self):
        return self.data;

    def getRight(self):
        data = self.data;
        data.reverse();
        return data;

tree2 = Tree("*");
tree2.appendRight(44);
tree2.appendLeft(20);

tree = Tree("+");
tree.appendRight(4);
tree.appendLeft(10);
tree.appendLeft(tree2);

print(tree.calculateLeft());

看起来Tree2和Tree正在共享列表"数据"?

目前,我希望它输出类似于[20,44],10,4]的内容,但是当我

1
tree.appendLeft(tree2)

我得到了RuntimeError: maximum recursion depth exceeded,当我甚至不愿意appendLeft(tree2)时,它输出[10, 20, 44, 4]!!!!)我在这里错过了什么?我使用的是可移植的python 3.0.1。

谢谢你


问题是,您已经将data声明为类变量,因此类的所有实例共享相同的列表。相反,把self.data = []放在你的__init__中。

另外,去掉所有的分号。它们是不必要的,会使代码混乱。


将根和数据移动到EDOCX1的定义中(2)。现在,您已经将它们定义为类属性。这使得它们在树类的所有实例之间共享。当您实例化两个树(treetree2时,它们都共享与self.data访问的同一列表。要使每个实例都有自己的实例属性,必须将声明移动到__init__函数中。

1
2
3
def __init__(self, equation):
    self.root = equation
    self.data = []

此外,使用

1
        if isinstance(item,Tree):        # This is True if item is a subclass of Tree

而不是

1
        if (type(item) == type(self)):   # This is False if item is a subclass of Tree

变化

1
data = self.data

1
data = self.data[:]

getRight中。当你说data = self.data时,变量名data指向与self.data指向相同的列表。当你随后反转data时,你也反转self.data。要仅反转data,必须复制列表。self.data[:]使用切片表示法返回列表的副本。注意,self.data的元素可以是trees,self.dataself.data[:]可以包含相同的元素。我认为您的代码不需要复制这些元素,但是如果是这样的话,您需要递归地复制self.data

1
2
3
4
def getRight(self):
    data = self.data[:]
    data.reverse()
    return data


当您以以下方式定义属性时:

1
2
3
class Tree:
    root = None
    data = []

..这个空列表对象是按照python定义类的方式创建的,而不是在创建新实例时创建的。它是类属性,而不是实例属性。也就是说,Tree.root在所有情况下都是相同的对象:

1
2
3
4
5
6
7
8
class Tree:
    root = None
    data = []

t1 = Tree()
t2 = Tree()

print id(t1.data) == id(t2.data) # is True, they are the same object

要获得预期的行为,请将创建空列表的操作移动到__init__函数,该函数仅在创建新实例时调用,并且只更改该实例(正如它分配给self的那样):

1
2
3
4
5
6
7
8
9
class Tree:
    def __init__(self):
        self.root = None
        self.data = []

t1 = Tree()
t2 = Tree()

print id(t1.data) == id(t2.data) # False, they are different objects

这个问题解释了为什么这种行为是有用的