Как объединить два словаря в один таким образом, чтобы связывались ссылки

Допустим есть следующие словари:


    dict1 = dict()
    dict2 = dict()
    dict1["поле"] = 1
    dict2["кукуруза"] = 2
    dictunion = dict()

Как в dictunion записать dict1 и dict2, т.е. привести к виду { "поле": 1 "кукуруза": 2 } , чтобы после изменения значений dict1 и dict2, допустим "поле": 10, а "кукуруза": 20 при выводе dictunion получилось следующее: { "поле": 10 "кукуруза": 20 }


Ответы (4 шт):

Автор решения: Sky
x = dict1 | dict2
print(x)

просто оператор объеденения |

→ Ссылка
Автор решения: Сергей Шашко
>>> x = {"key1": "value1 from x", "key2": "value2 from x"}
>>> y = {"key2": "value2 from y", "key3": "value3 from y"}
# объединение словаря `x` с `y`
>>> {**x, **y}
# {'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
# объединение словаря `y` с `x`
>>> {**y, **x}
# {'key2': 'value2 from x', 'key3': 'value3 from y', 'key1': 'value1 from x'}

# Новое в Python 3.9
>>> x | y
# {'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
>>> y | x
# {'key2': 'value2 from x', 'key3': 'value3 from y', 'key1': 'value1 from x'}
→ Ссылка
Автор решения: FindMeTomorrow

Если нужно использовать именно словарь, то никак. Python не позволит это сделать. В новый словарь всегда будут помещаться новые ссылки. Для лучшего понимания механизма рекомендую почитать про изменяемые и неизменяемые объекты.

Если же использование именно словарей не принципиально, то можно реализовать собственный класс с использованием __getitem__ и __setitem__, чтобы обращаться к полям с помощью ключей.

Например так:

class MyDict(object):
    def __init__(self, inner_dict: dict):
        self.inner_dict = inner_dict

    def __getitem__(self, item):
        return self.inner_dict[item]

    def __setitem__(self, key, value):
        self.inner_dict[key] = value


class MyDictUnion(object):
    def __init__(self, my_dict_1: MyDict, my_dict_2: MyDict):
        self.my_dict_1 = my_dict_1
        self.my_dict_2 = my_dict_2

    def __getitem__(self, item):
        if item in self.my_dict_1.inner_dict:
            return self.my_dict_1[item]
        elif item in self.my_dict_2.inner_dict:
            return self.my_dict_2[item]

    def __setitem__(self, key, value):
        if key in self.my_dict_1.inner_dict:
            self.my_dict_1[key] = value
        elif key in self.my_dict_2.inner_dict:
            self.my_dict_2[key] = value


dict1 = MyDict({"поле": 1})
dict2 = MyDict({"кукуруза": 2})
dictunion = MyDictUnion(dict1, dict2)

dict1["поле"] = 10
print(dictunion["поле"])

Небольшое дополнение:

Класс MyDict, который я почему-то посчитал обязательным, на самом деле совершенно не нужен. Соответственно от него можно избавиться. А если в DictUnion дополнительно реализовать метод keys, то, в случае необходимости, объект можно будет преобразовать в словарь с помощью dict(dictunion). Но стоит учитывать, что это будет новый словарь, значения которого никак не зависят от dict1, dict2 и dictunion.

Моя реализация:

class DictUnion(object):
    def __init__(self, dict_1: dict, dict_2: dict):
        self.dict_1 = dict_1
        self.dict_2 = dict_2

    def __getitem__(self, item):
        if item in self.dict_1:
            return self.dict_1[item]
        else:
            return self.dict_2[item]

    def __setitem__(self, key, value):
        if key in self.dict_1:
            self.dict_1[key] = value
        else:
            self.dict_2[key] = value

    def keys(self):
        return self.dict_1.keys() | self.dict_2.keys()
→ Ссылка
Автор решения: Stanislav Volodarskiy

Простейший изменяемый объект – список из одного элемента. Да, изменится синтаксис, но вы получите полноценное разделяемое значение:

dict1 = dict()
dict2 = dict()
dict1["поле"] = [1]            # вместо значений храним списки
dict2["кукуруза"] = [2]        # из одного элемента
dictunion = dict1 | dict2

print(dictunion)
dict1["поле"][0] = 10          # ко всем обращениям
dict2["кукуруза"][0] = 20      # приписываем `[0]`
print(dictunion)
$ python refs.py
{'поле': [1], 'кукуруза': [2]}
{'поле': [10], 'кукуруза': [20]}
→ Ссылка