Python范围/静态误解

6 投票
4 回答
520 浏览
提问于 2025-04-15 15:33

我真的搞不懂为什么下面的代码块1会输出结果1,而不是结果2?

代码块1:

class FruitContainer:
       def __init__(self,arr=[]):
           self.array = arr
       def addTo(self,something):
           self.array.append(something)
       def __str__(self):
           ret = "["
           for item in self.array:
               ret = "%s%s," % (ret,item)
           return "%s]" % ret

arrayOfFruit = ['apple', 'banana', 'pear']
arrayOfFruitContainers = []

while len(arrayOfFruit) > 0:
   tempFruit = arrayOfFruit.pop(0)
   tempB = FruitContainer()
   tempB.addTo(tempFruit)
   arrayOfFruitContainers.append(tempB)

for container in arrayOfFruitContainers:
   print container 

**Output 1 (actual):**
[apple,banana,pear,]
[apple,banana,pear,]
[apple,banana,pear,]

**Output 2 (desired):**
[apple,]
[banana,]
[pear,]

这段代码的目的是遍历一个数组,把每个元素放到一个父对象里。这是我实际代码的简化版,实际代码是把所有的苹果放到一个苹果袋里,依此类推。我猜可能是因为某种原因,它要么在使用同一个对象,要么就像水果容器使用了一个静态数组一样。我不知道该怎么解决这个问题。

4 个回答

1

正如Ned所说,你的问题在于你把一个列表当作默认参数使用了。这里有更多的细节可以查看这里。解决办法是把__init__函数改成下面这样:

       def __init__(self,arr=None):
           if arr is not None:
               self.array = arr
           else:
               self.array = []
8

你绝对不要把可变的值(比如空列表 [])作为方法的默认参数。这个值只会计算一次,然后在每次调用这个方法的时候都用同一个值。如果你把一个空列表当作默认值,那么每次调用这个方法而没有提供参数时,都会使用同一个列表,哪怕这个列表在之前的函数调用中已经被修改过了。

可以这样做:

def __init__(self,arr=None):
    self.array = arr or []
2

你的代码在初始化类的时候使用了一个默认参数。这个默认参数的值只在编译时计算一次,所以每次创建的实例都会用同一个列表来初始化。你可以这样修改:

def __init__(self, arr=None):
    if arr is None:
        self.array = []
    else:
        self.array = arr

我在这里详细讨论过这个问题:如何在Python中定义一个类

撰写回答