是否有一种方法重命名字典键,而不重新分配其值为一个新名称和删除旧的名称键;并且没有通过dict键/值迭代?

在OrderedDict的情况下,做同样的事情,同时保持该键的位置。


当前回答

我使用@wim的答案上面,dict.pop()重命名键时,但我发现了一个问题。循环遍历dict以更改键,而没有将旧键列表与dict实例完全分离,结果将新的、已更改的键循环到循环中,并丢失一些现有的键。

首先,我是这样做的:

for current_key in my_dict:
    new_key = current_key.replace(':','_')
    fixed_metadata[new_key] = fixed_metadata.pop(current_key)

我发现,以这种方式循环字典,字典一直在找到键,即使它不应该,也就是说,新的键,我已经改变的那些!我需要将实例彼此完全分开,以(a)避免在for循环中找到我自己更改的键,以及(b)找到由于某种原因在循环中没有找到的一些键。

我现在正在做这件事:

current_keys = list(my_dict.keys())
for current_key in current_keys:
    and so on...

必须将my_dict.keys()转换为列表,以摆脱对不断变化的dict的引用。仅使用my_dict.keys()将我与原始实例绑定在一起,并产生奇怪的副作用。

其他回答

Python 3.6(以后?)我会用下面的一句话

test = {'a': 1, 'old': 2, 'c': 3}
old_k = 'old'
new_k = 'new'
new_v = 4  # optional

print(dict((new_k, new_v) if k == old_k else (k, v) for k, v in test.items()))

生产

{'a': 1, 'new': 4, 'c': 3}

可能值得注意的是,如果没有打印语句,ipython控制台/jupyter笔记本将按照它们选择的顺序显示字典…

假设你想把键k3重命名为k4:

temp_dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
temp_dict['k4']= temp_dict.pop('k3')

我结合了上面帖子中的一些答案,并提出了下面的解决方案。虽然它很简单,但它可以用作从字典中进行更复杂的键更新的构建块。

test_dict = {'a': 1, 'b': 2, 'c': 3}
print(test_dict)
# {'a': 1, 'b': 2, 'c': 3}
prefix = 'up'
def dict_key_update(json_file):    
    new_keys = []
    old_keys = []
    for i,(key,value) in enumerate(json_file.items()):
        old_keys.append(key)
        new_keys.append(str(prefix) + key) # i have updated by adding a prefix to the 
        # key
    for old_key, new_key in zip(old_keys,new_keys):
        print('old {}, new {}'.format(old_key, new_key))
        if new_key!=old_key:  
           json_file[new_key] = json_file.pop(old_key)
     return json_file

test_dict = dict_key_update(test_dict)
print(test_dict)
# {'upa': 1, 'upb': 2, 'upc': 3}

我想出了这个函数,它不会改变原来的字典。这个函数也支持字典列表。

import functools
from typing import Union, Dict, List


def rename_dict_keys(
    data: Union[Dict, List[Dict]], old_key: str, new_key: str
):
    """
    This function renames dictionary keys

    :param data:
    :param old_key:
    :param new_key:
    :return: Union[Dict, List[Dict]]
    """
    if isinstance(data, dict):
        res = {k: v for k, v in data.items() if k != old_key}
        try:
            res[new_key] = data[old_key]
        except KeyError:
            raise KeyError(
                "cannot rename key as old key '%s' is not present in data"
                % old_key
            )
        return res
    elif isinstance(data, list):
        return list(
            map(
                functools.partial(
                    rename_dict_keys, old_key=old_key, new_key=new_key
                ),
                data,
            )
        )
    raise ValueError("expected type List[Dict] or Dict got '%s' for data" % type(data))

我使用@wim的答案上面,dict.pop()重命名键时,但我发现了一个问题。循环遍历dict以更改键,而没有将旧键列表与dict实例完全分离,结果将新的、已更改的键循环到循环中,并丢失一些现有的键。

首先,我是这样做的:

for current_key in my_dict:
    new_key = current_key.replace(':','_')
    fixed_metadata[new_key] = fixed_metadata.pop(current_key)

我发现,以这种方式循环字典,字典一直在找到键,即使它不应该,也就是说,新的键,我已经改变的那些!我需要将实例彼此完全分开,以(a)避免在for循环中找到我自己更改的键,以及(b)找到由于某种原因在循环中没有找到的一些键。

我现在正在做这件事:

current_keys = list(my_dict.keys())
for current_key in current_keys:
    and so on...

必须将my_dict.keys()转换为列表,以摆脱对不断变化的dict的引用。仅使用my_dict.keys()将我与原始实例绑定在一起,并产生奇怪的副作用。