簡體   English   中英

無法正確修改 Python class 中的字典

[英]Can't properly modify dictionary in Python class

我在嘗試修改 class 中的字典列表時遇到了一個奇怪的問題。 這是顯示該行為的最小可重現代碼:

from itertools import product

class Test():
    def __init__(self, grid):
        self.grid = grid
        self.pc =  [dict(zip(self.grid, v)) for v in product(*self.grid.values())]
        for i in range(0, len(self.pc)):
            self.pc[i]['sim_options']['id'] = i

grid = {
    'k': [5, 10, 15, 20],
    'sim_options': [
        {'name': 'cosine', 'batched': True},
        {'name': 'pearson', 'batched': True}
    ]
}
t = Test(grid)

我對 output 的期望如下:

[{'k': 5, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 0}},
 {'k': 5, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 1}},
 {'k': 10, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 2}},
 {'k': 10, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 3}},
 {'k': 15, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 4}},
 {'k': 15, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 5}},
 {'k': 20, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 6}},
 {'k': 20, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 7}}]

但我得到:

[{'k': 5, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 6}},
 {'k': 5, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 7}},
 {'k': 10, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 6}},
 {'k': 10, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 7}},
 {'k': 15, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 6}},
 {'k': 15, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 7}},
 {'k': 20, 'sim_options': {'name': 'cosine', 'batched': True, 'id': 6}},
 {'k': 20, 'sim_options': {'name': 'pearson', 'batched': True, 'id': 7}}]

我不明白我做錯了什么,我沒有遍歷列表,訪問第 i 個列表的'sim_options'字段並在該字典中創建一個新的鍵值對(“id”:i) ?

似乎字典正在通過引用進行更新,所以無論你對一個做什么,都會發生在另一個身上。

您可以使用id() function 進行檢查:

for i in range(0, len(self.pc)):
    print(id(self.pc[i]['sim_options']))
    self.pc[i]['sim_options']['id'] = i

這為'sim_options'中的兩個字典提供了相同的重復引用標識( 20789353511042078964975104 ):

2078935351104
2078964975104
2078935351104
2078964975104
2078935351104
2078964975104
2078935351104
2078964975104

解決此問題的一種方法是復制選項,這將為您提供不同的參考身份。 我已經稍微修改了您的代碼,以便使用copy()實現這一點。 它還使用enumerate()來循環索引和項目,當你需要兩者時,它比range(len(...))更好用。

from itertools import product
from pprint import pprint

class Test:
    def __init__(self, grid):
        self.grid = grid

        self.pc = []
        for i, (k, options) in enumerate(product(self.grid["k"], self.grid["sim_options"])):
            temp = {"k": k, "sim_options": options.copy()}
            temp["sim_options"]["id"] = i
            self.pc.append(temp)

    def get(self):
        return self.pc

grid = {
    "k": [5, 10, 15, 20],
    "sim_options": [
        {"name": "cosine", "batched": True},
        {"name": "pearson", "batched": True},
    ],
}

t = Test(grid)

pprint(t.get())

或者只是使用列表理解構建一個新的字典列表。 我通常覺得這種方式更可取。

self.pc = [
    {"k": k, "sim_options": {**option, "id": idx}}
    for idx, (k, option) in enumerate(
        product(self.grid["k"], self.grid["sim_options"])
    )
]

Output:

[{'k': 5, 'sim_options': {'batched': True, 'id': 0, 'name': 'cosine'}},
 {'k': 5, 'sim_options': {'batched': True, 'id': 1, 'name': 'pearson'}},
 {'k': 10, 'sim_options': {'batched': True, 'id': 2, 'name': 'cosine'}},
 {'k': 10, 'sim_options': {'batched': True, 'id': 3, 'name': 'pearson'}},
 {'k': 15, 'sim_options': {'batched': True, 'id': 4, 'name': 'cosine'}},
 {'k': 15, 'sim_options': {'batched': True, 'id': 5, 'name': 'pearson'}},
 {'k': 20, 'sim_options': {'batched': True, 'id': 6, 'name': 'cosine'}},
 {'k': 20, 'sim_options': {'batched': True, 'id': 7, 'name': 'pearson'}}]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM