Python3.4 字典值替换问题

Python3.4 Dictionary value replacement issue

我有一些代码可以获取字典列表并创建另一个字典列表。 列表中的每个字典都有两个 key/value 对 "ID" 和 "opcode",其中 "opcode" 是一个 32 位数。

我的代码需要创建第二个字典列表,其中操作码是分开的,即操作码=5 的字典将变成操作码=1 和操作码=4 的两个字典。

(opcode是一个32位的数字,我的要求是只有1位为高,即opcode=1,2,4,8,16等)

我已将问题简化为以下内容;我的代码需要把这个:

part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]

进入这个:

part_=[{"ID":1,"opcode":4},{"ID":2,"opcode":1},{"ID":2,"opcode":4},{"ID":3,"opcode":2},{"ID":3,"opcode":4}]

目前我的代码如下

def bit_set(theNumber,bit):
    return theNumber&(1<<bit)!=0

part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]

part_=[]
for i in part:
    for j in range(32):
        if bit_set(i["opcode"],j):
            part_.append(i)
            part_[-1]["opcode"]=(1<<j)

for i in part_:
    print(i)

代码的输出是:

{'opcode': 4, 'ID': 1}
{'opcode': 1, 'ID': 2}
{'opcode': 2, 'ID': 3}

有趣的是,如果我稍微修改代码使得值修改行不存在,额外的字典 创建的,但显然操作码不正确。

def bit_set(theNumber,bit):
    return theNumber&(1<<bit)!=0

part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]

part_=[]
for i in part:
    for j in range(32):
        if bit_set(i["opcode"],j):
            part_.append(i)
            #part_[-1]["opcode"]=(1<<j)

for i in part_:
    print(i)

输出为

{'ID': 1, 'opcode': 4}
{'ID': 2, 'opcode': 5}
{'ID': 2, 'opcode': 5}
{'ID': 3, 'opcode': 6}
{'ID': 3, 'opcode': 6}

我可以通过以不同的方式解决问题来解决这个问题,但是为了了解正在发生的事情,我无法理解。

这是因为当您将 i 附加到新列表时,您没有创建字典的副本,而是添加了对原始字典的引用。这意味着当您在下一行更改字典时,您也会更改 part 中的值。这导致循环不再匹配操作码的任何部分。如果您在代码末尾打印出 part 的值,您可以看到这一点。

python 文档解释为:

Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other. Reference

您可以通过在追加字典时创建字典的副本来解决此问题。这将允许您在不影响原始字典的情况下更改值。 Python 允许您使用 copy 模块 (Documentation) 复制对象。

只需导入 copy 然后执行 part_.append(copy.copy(i)) 而不是 part_.append(i)

import copy

def bit_set(theNumber,bit):
    return theNumber&(1<<bit)!=0

part = [{"ID": 1, "opcode": 4}, {"ID": 2, "opcode": 5}, {"ID": 3, "opcode": 6}]

part_=[]
for i in part:
    for j in range(32):
        if bit_set(i["opcode"],j):
            part_.append(copy.copy(i))
            part_[-1]["opcode"]=(1<<j)

for i in part_:
    print(i)