我以前的Python值如何在此字典中被覆盖?

时间:2018-07-09 18:53:10

标签: python dictionary

我正在尝试更新字典,但是以前的值一直被覆盖。这是我正在使用的代码的简化版本。

selected_session = ""
encounters_to_add = []
session_encounters = {}

selected_session = "Session 1: Paint it Black"
encounters_to_add.append("Meet the Town (Narrative)")
session_encounters[selected_session] = encounters_to_add

encounters_to_add.append("Barn Bandits (Structured)")
session_encounters[selected_session] = encounters_to_add

encounters_to_add.clear()
selected_session = "Session 2: Myster Man"
encounters_to_add.append("A Crime Most Foul (Social)")
session_encounters[selected_session] = encounters_to_add

print(session_encounters)

我想回来

{'Session 1: Paint it Black': ['Meet the Town (Narrative)', 'Barn Bandits (Structured)'], 'Session 2: Mystery Man': ['A Crime Most Foul (Social)']}

相反,我回来了

{'Session 1: Paint it Black': ['A Crime Most Foul (Social)'], 'Session 2: Myster Man': ['A Crime Most Foul (Social)']}

我不明白以前的值是如何被覆盖的。由于我使用的是新密钥,因此应该在我脑海中将值添加到该密钥中。

3 个答案:

答案 0 :(得分:1)

那是因为您只是存储对在第二行中创建的列表实例的 引用

# Creates a new instance of a list where
# 'encounters_to_add' is the reference to this list
encounters_to_add = []  
# Stores only a copy of the 'reference' in your dictionary
session_encounters[selected_session] = encounters_to_add

这不是列表的副本 -似乎就是您所假设的-而是对该列表的引用的副本。

您对encounters_to_add所做的任何事情都会影响session_encounters[selected_session],因为

session_encounters[selected_session] = encounters_to_add
session_encounters[selected_session] is encounters_to_add # is True

或更清楚一点:

session_encounters['A'] = encounters_to_add
session_encounters['B'] = encounters_to_add

session_encounters['A'] is encounters_to_add # is True
session_encounters['B'] is encounters_to_add # is also True

您需要两个实例,例如:

encounters_to_add_1 = []  # An instance of a list
encounters_to_add_2 = []  # Another list instance

session_encounters = {}

selected_session = "Session 1: Paint it Black"
encounters_to_add_1.append("Meet the Town (Narrative)")
encounters_to_add_1.append("Barn Bandits (Structured)")
session_encounters[selected_session] = encounters_to_add_1   

selected_session = "Session 2: Myster Man"
encounters_to_add_2.append("A Crime Most Foul (Social)")
session_encounters[selected_session] = encounters_to_add_2

print(session_encounters)

输出:

{'Session 1: Paint it Black': ['Meet the Town (Narrative)', 'Barn Bandits (Structured)'], 'Session 2: Myster Man': ['A Crime Most Foul (Social)']}

这是另一个示例-尝试找出此处发生的情况:

my_list = list()
my_dict = {i: my_list for i in range(3)}
my_dict[0].append('Hello World!')
print(my_dict)

my_dict = {i: list() for i in range(3)}
my_dict[0].append('Hello World!')
print(my_dict)

你为什么得到:

{0: ['Hello World!'], 1: ['Hello World!'], 2: ['Hello World!']}
{0: ['Hello World!'], 1: [], 2: []}

答案 1 :(得分:1)

您只有3次插入字典的一个列表,第二次插入将覆盖第一个,因此实际上同一列表最后仅出现两次。在添加之间也要清除它,这就是为什么丢失两个原始条目的原因。只需在print(session_encounters)调用之后添加一个clear()

逐步引导您完成示例:

selected_session = ""
encounters_to_add = []
session_encounters = {}

selected_session = "Session 1: Paint it Black"
encounters_to_add.append("Meet the Town (Narrative)")
session_encounters[selected_session] = encounters_to_add

enter image description here

encounters_to_add.append("Barn Bandits (Structured)")
session_encounters[selected_session] = encounters_to_add

enter image description here

encounters_to_add.clear()

enter image description here

selected_session = "Session 2: Myster Man"
encounters_to_add.append("A Crime Most Foul (Social)")
session_encounters[selected_session] = encounters_to_add

enter image description here

解决方案很简单:始终创建新列表:

session_encounters = {}

selected_session = "Session 1: Paint it Black"
encounters_to_add = ["Meet the Town (Narrative)", "Barn Bandits (Structured)"]
session_encounters[selected_session] = encounters_to_add

selected_session = "Session 2: Myster Man"
encounters_to_add  ["A Crime Most Foul (Social)"]
session_encounters[selected_session] = encounters_to_add

print(session_encounters)

请注意,您也可以使用collections.defaultdict使其更加简单明了:

from collections import defaultdict

session_encounters = defaultdict(list)
session_encounters["Session 1: Paint it Black"].append("Meet the Town (Narrative)")
session_encounters["Session 1: Paint it Black"].append("Barn Bandits (Structured)")
session_encounters["Session 2: Myster Man"].append("A Crime Most Foul (Social)")

print(session_encounters)

答案 2 :(得分:0)

在python中,有两种传递/分配值的方式,按引用按值

  1. 传递引用:该对象收到对该对象的隐式引用,指向该值的原始位置。默认情况下,可变对象将通过引用传递。 (例如列表)
  2. 传递值:将创建该值的本地副本并将其链接到该对象。默认情况下,不可变对象将按值传递(例如,整数,字符串等)
      

    更新(贷记为 MSeifert ):请注意,默认情况下,Python始终会按引用分配。上述传递值实际上是由于某些对象类型的不可变性而发生的行为。阅读评论以获取更多详细信息/示例。

您面临的问题是,您将encounters_to_add列表(通过引用)传递到了字典sessions_encounters中,然后使用encounters_to_add.clear()方法重置了对象。这影响了所有对象关联(包括与"Session 1: Paint it Black"字典内的键session_encounters关联的值)。

要解决此问题,您需要按照以下代码按值传递encounters_to_add

  

请注意,唯一的区别在于第session_encounters[selected_session] = encounters_to_add[:]行的赋值,其中[:]将指示python创建列表的本地副本(按值传递)而不是通过引用传递它。

selected_session = ""
encounters_to_add = []
session_encounters = {}

selected_session = "Session 1: Paint it Black"
encounters_to_add.append("Meet the Town (Narrative)")

encounters_to_add.append("Barn Bandits (Structured)")
session_encounters[selected_session] = encounters_to_add[:]

encounters_to_add.clear()
selected_session = "Session 2: Myster Man"
encounters_to_add.append("A Crime Most Foul (Social)")
session_encounters[selected_session] = encounters_to_add[:]

print(session_encounters)

这将输出

{'Session 1: Paint it Black': ['Meet the Town (Narrative)', 'Barn Bandits (Structured)'], 'Session 2: Myster Man': ['A Crime Most Foul (Social)']}