4

我是 Python 的初学者,对赋值运算符理解不清楚,例如:

list1 = ["Tom", "Sam", "Jim"]
list2 = list1

上述两个语句将 'list1' 和 'list2' 绑定到["Tom", "Sam", "Jim"],问题是,如果一个运算符如下所示:

list1[1] = "Sam's sister",如果赋值语句也被认为是绑定的,那么list2[1]仍然与“Sam”相关联,结果是修改list1不影响list2,即使Python呈现相反的输出,另一个问题是是否list1[1]可以将其视为变量在 Python 中list1list2

任何人都可以有任何建议吗?

4

4 回答 4

4

在您的示例中,标识符list1list2是对同一基础对象的引用(只是同一事物的不同名称)。

id()可用于查看是否引用了相同的底层对象。

>>> list1 = ["Tom", "Sam", "Jim"]
>>> list2 = list1
>>> id(list1)
44259368
>>> id(list2)
44259368

要创建定义列表的副本,请使用[:]符号,或者deepcopy正如 Matthew 所提到的。您会注意到,完成此操作后,位置/id 已更改。

>>> list3 = list1[:]
>>> id(list3)
44280208

关于 id 命令:

>>> help(id)
Help on built-in function id in module __builtin__:

id(...)
    id(object) -> integer

    Return the identity of an object.  This is guaranteed to be unique among
    simultaneously existing objects.  (Hint: it's the object's memory address.)
于 2012-10-15T02:55:56.890 回答
3

你是对的,他们不一样。在 Python ( name = ...) 中对裸名称赋值与对其他任何事物的赋值是不同的操作。特别是它与项目分配(name[0] = ...)和属性分配(name.attr = ...)不同。它们都使用等号,但后两者可以通过钩子(__setitem____setattr__)进行操作,可以调用任意代码,并且通常在程序员的控制之下。对裸名称的分配不受 Python 程序员的控制。你不能影响它的作用;它总是将右侧绑定到左侧的名称。

这可能会令人困惑,因为人们习惯于认为等号是“赋值”的原因。但是在 Python 中,为了了解正在发生什么操作,你真的必须查看等号的左侧,看看分配给什么样的东西。

于 2012-10-15T02:32:02.647 回答
1

BrenBarn 对所有事情都是绝对正确的,但这里有另一种可能更容易理解的方式来看待它:

您的第一条语句使用这些值创建一个列表,然后让 list1 指向它。第二条语句使 list2 指向与 list1 完全相同的内存空间。(您可以通过在第二条语句之后对它们运行 id 来看到这一点)。

此时 list1 和 list2 本质上都是对同一个可变列表的引用。当您更改该列表时, list1 和 list2 仍然都引用相同的实际列表,并且使用其中任何一个来访问它都会给您同样的东西。

最近发表了一篇关于相关主题的博客文章,Python Conques the Universe 也在这里讨论了类似的主题。

于 2012-10-15T02:44:24.383 回答
0

BrenBam 对正在发生的事情有很好的解释。deepcopy一种解决方法:

>>> from copy import deepcopy
>>> list1 = ["Tom", "Sam", "Jim"]
>>> list2 = deepcopy(list1)
>>> list1[1] = "Sam's sister"
>>> list1
['Tom', "Sam's sister", 'Jim']
>>> list2
['Tom', 'Sam', 'Jim']

良好的编程风格将使其很少需要实际使用deepcopy

于 2012-10-15T02:38:48.407 回答