3

I have some trouble understanding what happens with class init arguments that are lists
like:

class A(object):
    def __init__(self, argument=[]):  
        self.argument = argument[:]  

or:

def __init__(self,argument=None):  
    self.arguments = arguments or []  

or:

def __init__(self, argument=[]):  
    self.argument = argument  

This can't be done because the default value for every A object would point to the same piece of memory. I can't really understand what happens here and how it happens.

4

3 回答 3

6

这是一个众所周知的python gotcha

基本上,该参数的默认值是在首次定义该方法时创建的,并且由于它是一个可变对象(在本例中为一个列表),因此即使它已更改,甚至在随后的调用中,它也只是引用同一个对象到方法。

处理这种情况的通常方法是像在第二个示例中那样对待它:

def __init__(self, arguments=None):  
    self.arguments = arguments or []

但是如果你想做的是有一个包含所有参数的列表,你可以只使用 Python 的参数 unpacking

它是这样工作的:

def my_function(*args):
    print args

然后,您将在您的方法中访问一个包含所有参数的元组。所以如果你这样调用你的函数:

>>> my_function(1, 2, 3)

您的输出将如下所示:

(1, 2, 3)

很酷的是,您总是可以以相反的方式使用它,因此,假设您有一个列表(或元组),并且您希望将列表中的每个项目作为位置参数传递给您的函数。你会这样做:

>>> my_list = [1, 2, 3]
>>> my_function(*my_list)

而且,就您的功能而言,它与之前的调用相同。

您应该阅读我指出的文档,以及更深入地定义函数的部分。

于 2010-01-31T06:04:18.880 回答
4

该列表是在定义运行时创建的,而不是在方法执行时创建的。

于 2010-01-31T05:45:02.613 回答
1

我认为这个问题有些不清楚,但我从中了解到的是,您想知道如何将一个类 init 传递给一个列表不会使内部对象与您传递的对象相同,而是一个副本。如果这不是问题,请告诉我,我将删除此答案。

简而言之,它是这样工作的:在 Python 中,没有任何内容按值存储为名称。一切都在内部存储为指向 Python 对象的指针。当你这样做时:

a = [1,2,3]
b = a

您没有设置b为. 您正在设置引用相同的对象。所以声明:ab

a is b

是的,因为名称引用了同一个对象。

a = [1,2,3]
b = [1,2,3]
a is b

这将返回错误。原因是现在您已经创建了两个不同的对象。所以这一行:

self.argument = argument[:]

是一种(必要的)制作副本的方式,self.argument以便它不引用同一个对象。

于 2010-01-31T05:49:51.980 回答