从具有不同键但具有相同ID的现有dicts创建新的python dict

时间:2015-08-10 01:45:23

标签: python dictionary

我有一个复合词典 d ,它是由一组组件词典构建的, d1 d2

d1 = {'key1': 4}
d2 = {'key2': 5}
d = {}
d['altname_key1'] = d1['key1']
d['altname_key2'] = d2['key2']

我想要完成的行为是更改 d 的键,以自动传播到 d1 d2 中的更改。上面的代码不是这样的,可以通过比较id来验证:

id(d['altname_key1']) == id(d1['key1'])
True 
id(d['altname_key2']) == id(d2['key2'])
True 
d['altname_key1'] = 17
id(d['altname_key1']) == id(d1['key1'])
False 

如果我的复合词典只是单个组件的组合,如果我没有更改键名,那么我正在寻找的行为可以实现:

d = d1
d['key1'] = 45
id(d['key1']) == id(d1['key1'])
True 

python是否具有启用复合词典 d 的功能,包括不同的键名,以便键指向内存中的相同点,即使键具有不同的名称?

2 个答案:

答案 0 :(得分:2)

我相信其他一些东西可能会导致id的值发生变化,也许你在测试d之前对id字典进行了一些其他的赋值,python中的数字是不可变的,所以两个不同的数字不会有相同的id

当你这样做时 - d['altname_key1'] = d1['a'] - Python通过赋值传递,这意味着d1['a']引用的引用按值传递。示例 -

>>> d = {'a':[1,2]}
>>> d2 = {'b':[3,4]}
>>> d3 = {}
>>> d3 ['aa'] = d['a']
>>> d3['bb'] = d2['b']
>>> d3
{'bb': [3, 4], 'aa': [1, 2]}

>>> id(d3['aa']) == id(d['a'])
True
>>> d3['aa'].append(5)

>>> d3
{'bb': [3, 4], 'aa': [1, 2, 5]}

>>> d
{'a': [1, 2, 5]}

所以你想要实现的目标确实有效。

但是这个给出,我想建议不要对同一个可变对象保持多个引用,因为这个方法可能导致神秘的错误,有些代码可能会错误地更新d字典,即使你不想要它和它可以导致相同的变化反映在d1中。调试问题很难。

此外,如果您在d上执行作业,此方法会中断,在这种情况下,d字典的值会发生变化,但d1d2不会更改。示例 -

>>> d3['aa'] = [1]
>>> d3
{'bb': [3, 4], 'aa': [1]}
>>> d
{'a': [1, 2, 5]}

您可能想重新考虑您要设计的内容。

关于为什么在执行以下操作时获得所需的行为 -

d = d1
d['key1'] = 45
id(d['key1']) == id(d1['key1'])
True 

这是因为d是对d1字典对象的引用,所以它们基本上指向相同的字典。因此d['key1']始终为d1['key1']。您可以执行以下操作以查看它们是相同的参考 -

id(d) == id(d1)

由于上述原因,不会再推荐这一点。

答案 1 :(得分:1)

这个类将像ChainMap一样,除了它将尊重你指定的备用键映射。它适用于Python 2.7和Python 3.3 +。

from __future__ import print_function

try:
    from collections import ChainMap  # Python 3
except ImportError:
    from ConfigParser import _Chainmap as ChainMap  # Python 2


class ChainMapWithAltKeys(ChainMap):
    def __init__(self, *maps, **kwargs):
        try:
            super(ChainMapWithAltKeys, self).__init__(*maps)
        except TypeError:  # Python 2
            ChainMap.__init__(self, *maps)  # Python 2
        self.altkeymap = kwargs.get('altkeymap', {})

    def __getitem__(self, key):
        if key in self.altkeymap:
            key = self.altkeymap[key]
        try:
            return super(ChainMapWithAltKeys, self).__getitem__(key)
        except TypeError:  # Python 2
            return ChainMap.__getitem__(self, key)  # Python 2


dict_one = {'a': 1, 'b': 2, 'c': 3, 'samekey': 'diffval_one'}
dict_two = {'x': 24, 'y': 25, 'z': 26, 'samekey': 'diffval_two'}

altkeymap = {'alpha': 'a', 'zulu': 'z'}

cmwak = ChainMapWithAltKeys(dict_one, dict_two, altkeymap=altkeymap)

print(cmwak['a'])  # 1
print(cmwak['alpha'])  # 1
print(cmwak['b'])  # 2
print(cmwak['y'])  # 25
print(cmwak['z'])  # 26
print(cmwak['zulu'])  # 26
print(cmwak['samekey'])  # diffval_one

请注意,当一个键位于多个dict中时,该值取自首先传递的dict;具体来说,按顺序检查cmwak.maps中的每个映射,直到找到密钥。阅读ChainMap了解详情;那里的所有内容都适用于ChainMapWithAltKeys