因此,当我创建一个类似下面的类时,我会遇到意外行为,看起来好像饮料类的实例正在共享“stock”变量,但是因为stock变量是在 init中声明的声明,我认为它应该仅限于一个实例。
class Beverage():
def __init__(self, owner, beverages=[]):
self.stock = beverages
self.owner = owner
def add_drink(self, beverage):
self.stock.append(beverage)
def get_drink(self, beverage):
if beverage in self.stock:
print "(%s) Has beverage (%s)!" %(self.owner,beverage)
self.stock.remove(beverage)
else:
print "(%s) Does not have beverage (%s)!" %(self.owner,beverage)
her = Beverage("her",["milkshake"])
me = Beverage("I")
you = Beverage("You")
you.add_drink("milkshake")
you.add_drink("punch")
her.get_drink("milkshake")
me.get_drink("milkshake")
me.add_drink("tea")
you.get_drink("milkshake")
输出
(her) Has beverage (milkshake)!
(I) Has beverage (milkshake)!
(You) Does not have beverage (milkshake)!
输出对我来说应该是:
(her) Has beverage (milkshake)!
(I) Does not have beverage (milkshake)!
(You) has beverage (milkshake)!
由于“你”和“她”将饮料“奶昔”添加到他们的股票中,但不知怎的“我”能够访问它,好像它是一个共享变量。当在StackOverflow上搜索类似的帖子时,我发现了一堆类似的帖子,其中编码器已经在类级别定义了变量,所以它们是有意义的,它们是共享的,但是这里的stock变量是在实例级别声明的,所以我假设Python会将其视为特定于实例。有关代码行为的原因的任何解释?
答案 0 :(得分:3)
me
和you
确实共享相同的饮料列表,这是参数的默认值。这是一个众所周知的问题 - 使用可变的默认值将导致默认值在对象发生变化时发生变化。
同样众所周知的答案是这样做:
def __init__(self, owner, beverages=None):
if beverages is None:
beverages = []
...
这可以保证为每个实例化创建一个全新的饮料清单。
编辑:if not beverages
不是一个充分的测试。用户完全有可能传入一个空列表,然后代码就会像没有参数时那样动作并创建一个新列表。因此,更明确的“如果饮料是没有的话”:
正如Ignacio Vazquez-Abrams所指出的,"Least Astonishment" and the Mutable Default Argument
中已经讨论了 ad nauseam答案 1 :(得分:2)
将列表用作默认值为a dangerous thing(列表beverages
指向同一列表)。您可以通过将beverages
的默认值设置为None
,然后添加行
if not beverages:
beverages = []