【问题标题】:python dictionary with list values - updating one key with a list updates all keys with the same list具有列表值的python字典 - 使用列表更新一个键会更新具有相同列表的所有键
【发布时间】:2018-03-05 17:11:24
【问题描述】:

我是 python 字典的新手,所以我不确定为什么会发生这种情况。基本上问题是每当我用列表更新一个键时,它都会用列表更新该字典中的所有键。 尝试,除了只有唯一用户,所以我认为这不是问题

    file:
    user contact
    20b3c296-0043-3948-9c90 Stacy Armstrong
    20b3c296-0043-3948-9c90 Brian Theresa
    20b3c296-0043-3948-9c90 Miller Justin
    c9b16828-91d2-33c9-b915 Monique Porter
    c9b16828-91d2-33c9-b915 Rebecca Marky
    c9b16828-91d2-33c9-b915 Rose Chang
    a6f8a71d-7568-3552-9cf4 Mildred Linda
    a6f8a71d-7568-3552-9cf4 Josephine Larry
    a6f8a71d-7568-3552-9cf4 Henry Mildred

代码如下:

for row in file:
    user = get_user(row)
    contact = get_contact(row)
    try:
        a = list_users.index(user)
    except ValueError:
        list_users.append(user)

        if len(list_users) > 1: # start from second user, and update previous one
            index = list_users.index(user)
            prev_user = list_users[index - 1]

            user_contacts.update({prev_user: list_contacts})    # update previous user with its list

            # print dict
            for key, value in user_contacts.items():
                print(key, value)
            print('\n')

        # clear list and add new contact (associated with new user)
        list_contacts.clear()
        list_contacts.append(contact)

    else:
        list_contacts.append(contact)

# update last user with its list
index = len(list_users)
prev_user = list_users[index - 1]

user_contacts.update({prev_user: list_contacts})

# print dict
for key, value in user_contacts.items():
    print(key, value)
print('\n')

打印语句给我:

20b3c296-0043-3948-9c90 ['Stacy Armstrong', 'Brian Theresa', 'Miller Justin']


20b3c296-0043-3948-9c90 ['Monique Porter', 'Rebecca Marky', 'Rose Chang']
c9b16828-91d2-33c9-b915 ['Monique Porter', 'Rebecca Marky', 'Rose Chang']


20b3c296-0043-3948-9c90 ['Mildred Linda', 'Josephine Larry', 'Henry Mildred']
c9b16828-91d2-33c9-b915 ['Mildred Linda', 'Josephine Larry', 'Henry Mildred']
a6f8a71d-7568-3552-9cf4 ['Mildred Linda', 'Josephine Larry', 'Henry Mildred']

即使 list_contacts 每次都不同(您可以尝试在更新字典之前打印它),但所有键值都会更新到该迭代中的最后一个列表。非常感谢任何帮助,因为我真的不知道这是什么原因。

谢谢你:)

【问题讨论】:

  • 这是一个按引用复制的问题——你所有的 dict-“值”都持有对相同数据的相同引用——一旦你使用一个引用来更新数据,你就修改了所有引用的基础数据.如果你想拥有不同且不同的列表,则需要在将其放入字典时copy.deepcopy()
  • 你看过defaultdict吗?这似乎是你需要的。首先像这样定义它:list_users = defaultdict(list) 然后像这样使用它:list_users[user].append(contact) 而不是整个 try-except 代码块。
  • @PatrickArtner 非常感谢,您的建议有效。但是为了澄清,这可以通过复制值而不是对列表的引用来避免,对吗?我认为这就是 deepcopy() 正在做的事情

标签: python python-3.x list dictionary


【解决方案1】:

这是一个按引用复制的问题——你所有的 dict-“值”都持有对相同数据的相同引用——一旦你使用一个引用来更新数据,你就修改了所有引用的基础数据。如果你想拥有不同且不同的列表,则需要在将其放入 dict 时对其进行 copy.deepcopy()。

您可以在 pyton 对象上使用 id() 获取唯一 ID,以区分/比较它们是“相同”还是“不同”,如下所示:

def pp (l, s):
    """silly pretty printer"""
    print(s+"\n")
    print("    ",id(l), l)
    for n in l:
        print("        ", id(n),n) 
        if n is type(list):
            for m in n:
                print("            ",id(m),m)
    print()


data         = [ [3,4] , "aa" ]              # a list, mutable
dataWithData = [ data, data, [99,100], 1]    # contains 2 refs to data, 1 new list 
                                             # if you append to dataWithData[1] both change

pp(dataWithData, "original list [ data, data, [99,100], 1]" )

dataWithData2 = dataWithData[:]  # shallow copy

pp(dataWithData2, "shallow copy of [ data, data, [99,100], 1]" ) 

import copy
dataWithData3 = copy.deepcopy( dataWithData)
pp(dataWithData3, "deepcopyed [ data, data, [99,100], 1]")

原名单[ data, data, [99,100], 1]

 764500835912 [[[3, 4], 'aa'], [[3, 4], 'aa'], [99, 100], 1]
     764497577480 [[3, 4], 'aa']
     764497577480 [[3, 4], 'aa']
     764500834824 [99, 100]
     1763008736 1

[ data, data, [99,100], 1]的浅拷贝

 # only the ref to the outer varname was changed - it is a new name but points
 # to all the old data 
 764500834888 [[[3, 4], 'aa'], [[3, 4], 'aa'], [99, 100], 1]
     764497577480 [[3, 4], 'aa'] # same
     764497577480 [[3, 4], 'aa'] # same
     764500834824 [99, 100]      # same
     1763008736 1                # same

深拷贝[ data, data, [99,100], 1]

 # all were changed, so all point to "new" data
 764500835400 [[[3, 4], 'aa'], [[3, 4], 'aa'], [99, 100], 1]
     764500834952 [[3, 4], 'aa']
     764500834952 [[3, 4], 'aa']
     764498168136 [99, 100]
     1763008736 1

复制并粘贴到您的编辑器中并玩转 - 更改内容并添加各种版本以查看遗留的内容(或检查 id)。

【讨论】:

    猜你喜欢
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    • 1970-01-01
    • 2019-10-05
    • 2019-11-19
    • 1970-01-01
    相关资源
    最近更新 更多