我真的坚持为什么以下代码块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,]
此代码的目标是遍历数组并将每个数据包装在父对象中。这是我的实际代码的减少,它将所有苹果添加到一袋苹果等等。我的猜测是,出于某种原因,它要么使用相同的对象,要么就像水果容器使用静态数组一样。我不知道如何解决这个问题。
答案 0 :(得分:8)
您永远不应该使用可变值(如[])作为方法的默认参数。该值计算一次,然后用于每次调用。当您使用空列表作为默认值时,每次在没有参数的情况下调用该方法时都会使用相同的列表,即使该值已被先前的函数调用修改。
请改为:
def __init__(self,arr=None):
self.array = arr or []
答案 1 :(得分:2)
您的代码有一个默认参数来初始化类。默认参数的值在编译时计算一次,因此每个实例都使用相同的列表进行初始化。像这样改变:
def __init__(self, arr=None):
if arr is None:
self.array = []
else:
self.array = arr
我在这里更充分地讨论了这个问题: How to define a class in Python
答案 2 :(得分:1)
正如Ned所说,问题是你使用列表作为默认参数。还有更多细节here。解决方案是更改__init__
功能,如下所示:
def __init__(self,arr=None):
if arr is not None:
self.array = arr
else:
self.array = []
答案 3 :(得分:0)
比传入None更好的解决方案 - 在这个特定的实例中,而不是一般 - 是将arr参数作为一个可枚举的项集来处理__init__,以预先初始化FruitContainer,而不是用于内部存储:
class FruitContainer:
def __init__(self, arr=()):
self.array = list(arr)
...
这将允许您传入其他可枚举类型来初始化容器,这是更高级的Python用户期望能够做到的:
myFruit = ('apple', 'pear') # Pass a tuple
myFruitContainer = FruitContainer(myFruit)
myOtherFruit = file('fruitFile', 'r') # Pass a file
myOtherFruitContainer = FruitContainer(myOtherFruit)
它还将化解另一个潜在的别名错误:
myFruit = ['apple', 'pear']
myFruitContainer1 = FruitContainer(myFruit)
myFruitContainer2 = FruitContainer(myFruit)
myFruitContainer1.addTo('banana')
'banana' in str(myFruitContainer2)
对于此页面上的所有其他实现,这将返回True,因为您不小心将容器的内部存储设为别名。
注意:此方法总是正确答案:“if not None”在其他情况下更好。只要问问自己:我是否传递了一组对象或一个可变容器?如果我传递我的对象的类/函数改变了我给它的存储,那会是(a)令人惊讶还是(b)可取的?在这种情况下,我认为它是(a);因此,list(...)调用是最佳解决方案。如果(b),“如果不是无”将是正确的方法。