Python实例变量显然共享数据

时间:2014-03-05 03:56:49

标签: python oop

因此,当我创建一个类似下面的类时,我会遇到意外行为,看起来好像饮料类的实例正在共享“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会将其视为特定于实例。有关代码行为的原因的任何解释?

2 个答案:

答案 0 :(得分:3)

meyou确实共享相同的饮料列表,这是参数的默认值。这是一个众所周知的问题 - 使用可变的默认值将导致默认值在对象发生变化时发生变化。

同样众所周知的答案是这样做:

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 = []