2

有人可以告诉我为什么当您复制字典时它们都指向同一个目录,因此对一个目录的更改会影响另一个目录,但列表不是这种情况?

我对他们为什么会以一种方式设置字典并列出另一种方式背后的逻辑感兴趣。这很令人困惑,如果我知道其背后的原因,我可能会记得。

dict = {'Dog' : 'der Hund' , 'Cat' : 'die Katze' , 'Bird' : 'der Vogel'}
otherdict = dict
dict.clear()
print otherdict

这导致 otherdict = {}。所以两个 dicts 都指向同一个目录。但列表并非如此。

list = ['one' , 'two' , 'three']
newlist = list
list = list + ['four']
print newlist

newlist 仍然保留旧列表。所以他们没有指向同一个目录。我想知道它们不同的原因背后的基本原理?

4

4 回答 4

4

一些与您的意图相似的代码将表明对一个列表的更改确实会影响其他引用。

>>> list = ['one' , 'two' , 'three']
>>> newlist = list
>>> list.append('four')
>>> print newlist
['one', 'two', 'three', 'four']

这是与您的字典代码最接近的类比。您在原始对象上调用方法。

不同之处在于您的代码使用了单独的加号和赋值运算符

list = list + ['four']

这是两个独立的操作。首先解释器对表达式求值list + ['four']。它必须将该计算的结果放入一个新的列表对象中,因为它不期望您将结果分配回列表。如果你说other_list = list + ['four'],如果列表被修改,你会很生气。

现在有一个新对象,包含 的结果list + ['four']。该新对象被分配给列表。list 现在是对新对象的引用,而 newlist 仍然是对旧对象的引用。

即使这是不同的

list += ['four']

+= 对可变对象的含义是它将修改对象。

于 2013-06-17T03:26:24.303 回答
4

您的两个案例对您正在复制的对象执行不同的操作,这就是您看到不同结果的原因。

首先,您并没有真正复制它们。您只需创建新的“引用”或(在更多 Python 术语中)将新名称绑定到相同的对象。

使用字典,您正在调用dict.clear,它会丢弃所有内容。这会修改现有对象,因此您可以通过对它的两个引用来查看结果。

使用该列表,您可以将其中一个名称重新绑定到一个新列表。这个新列表与保持不变的旧列表不同。

如果需要,您可以使用列表重新创建字典代码的行为。切片分配是一次修改整个列表的一种方法:

old_list[:] = [] # empties the list in place

一个附录,与上述主要问题无关:在您自己的代码中使用类似dict和作为变量的名称是一个非常糟糕的主意。list那是因为这些是内置 Python 字典和列表类型的名称。通过使用相同的名称,您会隐藏内置名称,这可能会导致令人困惑的错误。

于 2013-06-17T03:27:11.047 回答
3

在您的字典示例中,您创建了一个字典并将其存储在dict. 然后,您将相同的引用存储在otherdict. 现在两者都dict指向otherdict同一个字典*. 然后你打电话dict.clear()。这将清除dictotherdict指向的字典。

在您的列表示例中,您创建了一个列表并将其存储在list. 然后,您将相同的引用存储在otherlist. 然后创建一个由 的元素list和另一个元素组成的新列表,并将列表存储list. 您没有修改您创建的原始列表。您创建了一个新列表并更改了list指向的内容。

list.append('four')您可以使用而不是让您的列表示例显示与字典示例相同的行为list = list + ['four']

于 2013-06-17T03:24:29.257 回答
1

你是这个意思吗?

>>> d = {'test1': 1, 'test2': 2}
>>> new_d = d
>>> new_d['test3'] = 3
>>> new_d
{'test1': 1, 'test3': 3, 'test2': 2}
>>> d # copied over
{'test1': 1, 'test3': 3, 'test2': 2}
>>> lst = [1, 2, 3]
>>> new_lst = lst
>>> new_lst.append(5)
>>> new_lst
[1, 2, 3, 5]
>>> lst # copied over
[1, 2, 3, 5]
>>> new_lst += [5]
>>> lst # copied over
[1, 2, 3, 5, 5]
>>> my_tuple = (1, 2, 3)
>>> new_my_tuple = my_tuple
>>> new_my_tuple += (5,)
>>> new_my_tuple
(1, 2, 3, 5)
>>> my_tuple # immutable, so it is not affected by new_my_tuple
(1, 2, 3)

列表传递引用,而不是对象本身。大多数(犹豫说全部)可变(可以更改,例如列表和字典)对象传递引用,而不可变(不能更改,例如元组)对象传递对象本身。

于 2013-06-17T02:54:22.167 回答