更改字典中键的名称

2024-12-31 08:37:00
admin
原创
112
摘要:问题描述:如何更改 Python 字典中条目的键?解决方案 1:只需两步即可轻松完成:dictionary[new_key] = dictionary[old_key] del dictionary[old_key] 或者只需一步:dictionary[new_key] = dictionary.pop(ol...

问题描述:

如何更改 Python 字典中条目的键?


解决方案 1:

只需两步即可轻松完成:

dictionary[new_key] = dictionary[old_key]
del dictionary[old_key]

或者只需一步:

dictionary[new_key] = dictionary.pop(old_key)

KeyError如果dictionary[old_key]未定义,则将引发。请注意,这删除dictionary[old_key]

>>> dictionary = { 1: 'one', 2:'two', 3:'three' }
>>> dictionary['ONE'] = dictionary.pop(1)
>>> dictionary
{2: 'two', 3: 'three', 'ONE': 'one'}
>>> dictionary['ONE'] = dictionary.pop(1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
KeyError: 1

解决方案 2:

如果你想改变所有的键:

d = {'x':1, 'y':2, 'z':3}
d1 = {'x':'a', 'y':'b', 'z':'c'}

In [10]: dict((d1[key], value) for (key, value) in d.items())
Out[10]: {'a': 1, 'b': 2, 'c': 3}

如果您想更改单个键:您可以采用上述任何建议。

解决方案 3:

新鲜汽水

>>>a = {1:2, 3:4}
>>>a[5] = a.pop(1)
>>>a
{3: 4, 5: 2}
>>> 

解决方案 4:

在 Python 2.7 及更高版本中,您可以使用字典理解:这是我在使用 DictReader 读取 CSV 时遇到的一个例子。用户在所有列名后加上了“:”

ori_dict = {'key1:' : 1, 'key2:' : 2, 'key3:' : 3}

去掉键结尾的‘:’:

corrected_dict = { k.replace(':', ''): v for k, v in ori_dict.items() }

解决方案 5:

d = {1:2,3:4}

假设我们要将键更改为列表元素 p=['a', 'b']。以下代码即可:

d=dict(zip(p,list(d.values()))) 

我们得到

{'a': 2, 'b': 4}

解决方案 6:

由于键是字典用来查找值的,因此您无法真正更改它们。您可以做的最接近的事情是保存与旧键关联的值,删除它,然后使用替换键和保存的值添加新条目。其他几个答案说明了可以实现此目的的不同方法。

解决方案 7:

您可以使用 iff/else 字典理解。此方法允许您在一行中替换任意数量的键,并且不需要您更改所有键。

key_map_dict = {'a':'apple','c':'cat'}
d = {'a':1,'b':2,'c':3}
d = {(key_map_dict[k] if k in key_map_dict else k):v  for (k,v) in d.items() }

返回{'apple':1,'b':2,'cat':3}

解决方案 8:

没有直接的方法可以做到这一点,但你可以删除然后分配

d = {1:2,3:4}

d[newKey] = d[1]
del d[1]

或者进行批量密钥修改:

d = dict((changeKey(k), v) for k, v in d.items())

解决方案 9:

如果你有一个复杂的字典,则意味着字典中有一个字典或列表:

myDict = {1:"one",2:{3:"three",4:"four"}}
myDict[2][5] = myDict[2].pop(4)
print myDict

Output
{1: 'one', 2: {3: 'three', 5: 'four'}}

解决方案 10:

转换字典中的所有键

假设这是你的字典:

>>> sample = {'person-id': '3', 'person-name': 'Bob'}

要将示例字典键中的所有破折号转换为下划线:

>>> sample = {key.replace('-', '_'): sample.pop(key) for key in sample.keys()}
>>> sample
>>> {'person_id': '3', 'person_name': 'Bob'}

解决方案 11:

此函数获取一个字典,以及另一个指定如何重命名键的字典;它返回一个带有重命名键的新字典:

def rekey(inp_dict, keys_replace):
    return {keys_replace.get(k, k): v for k, v in inp_dict.items()}

测试:

def test_rekey():
    assert rekey({'a': 1, "b": 2, "c": 3}, {"b": "beta"}) == {'a': 1, "beta": 2, "c": 3}

解决方案 12:

假设需要一次性更改所有键。下面是我对这些键进行词干处理。

a = {'making' : 1, 'jumping' : 2, 'climbing' : 1, 'running' : 2}
b = {ps.stem(w) : a[w] for w in a.keys()}
print(b)
>>> {'climb': 1, 'jump': 2, 'make': 1, 'run': 2} #output

解决方案 13:

这将使所有字典键都变成小写。即使您有嵌套字典或列表。您可以执行类似操作来应用其他转换。

def lowercase_keys(obj):
  if isinstance(obj, dict):
    obj = {key.lower(): value for key, value in obj.items()}
    for key, value in obj.items():         
      if isinstance(value, list):
        for idx, item in enumerate(value):
          value[idx] = lowercase_keys(item)
      obj[key] = lowercase_keys(value)
  return obj 
json_str = {"FOO": "BAR", "BAR": 123, "EMB_LIST": [{"FOO": "bar", "Bar": 123}, {"FOO": "bar", "Bar": 123}], "EMB_DICT": {"FOO": "BAR", "BAR": 123, "EMB_LIST": [{"FOO": "bar", "Bar": 123}, {"FOO": "bar", "Bar": 123}]}}

lowercase_keys(json_str)


Out[0]: {'foo': 'BAR',
 'bar': 123,
 'emb_list': [{'foo': 'bar', 'bar': 123}, {'foo': 'bar', 'bar': 123}],
 'emb_dict': {'foo': 'BAR',
  'bar': 123,
  'emb_list': [{'foo': 'bar', 'bar': 123}, {'foo': 'bar', 'bar': 123}]}}

解决方案 14:


用下划线替换字典键中的空格,我使用这个简单的方法......

for k in dictionary.copy():
    if ' ' in k:
        dictionary[ k.replace(' ', '_') ] = dictionary.pop(k, 'e r r')

或者只是 dictionary.pop(k) 注意“er r”(可以是任何字符串)将成为新值,如果该键不在字典中,则无法替换它,而这在这里是不可能发生的。该参数是可选的,在其他类似的代码中,可能会发生 KeyError,添加的参数可以避免这种情况,但仍然可以使用该“er r”或您将其设置为任何值的新键。

.copy() 避免...字典在迭代过程中改变大小。

.keys() 不需要,k 是每个键,在我看来 k 代表键。

(我使用的是 v3.7)

有关字典 pop() 的信息

上面循环的一行代码是什么?

解决方案 15:

注意弹出的位置:

将要删除的键放在 pop() 之后

orig_dict['AAAAA'] = orig_dict.pop('A')

orig_dict = {'A': 1, 'B' : 5,  'C' : 10, 'D' : 15}   
# printing initial 
print ("original: ", orig_dict) 

# changing keys of dictionary 
orig_dict['AAAAA'] = orig_dict.pop('A')
  
# printing final result 
print ("Changed: ", str(orig_dict)) 

解决方案 16:

我只需要帮助我的妻子为 Python 课程做一些类似的事情,所以我编写了这段代码来向她展示如何做。正如标题所说,它只替换了一个键名。很少需要替换一个键名,并保持字典的顺序不变,但无论如何我还是想分享一下,因为这篇文章是 Goggle 搜索时返回的内容,尽管这是一个非常古老的帖子。

代码:

dictionary = {
    "cat": "meow",
    "dog": "woof",
    "cow": "ding ding ding",
    "goat": "beh"
}


def countKeys(dictionary):
    num = 0
    for key, value in dictionary.items():
        num += 1
    return num


def keyPosition(dictionary, search):
    num = 0
    for key, value in dictionary.items():
        if key == search:
            return num
        num += 1


def replaceKey(dictionary, position, newKey):
    num = 0
    updatedDictionary = {}
    for key, value in dictionary.items():
        if num == position:
            updatedDictionary.update({newKey: value})
        else:
            updatedDictionary.update({key: value})
        num += 1
    return updatedDictionary


for x in dictionary:
    print("A", x, "goes", dictionary[x])
    numKeys = countKeys(dictionary)

print("There are", numKeys, "animals in this list.
")
print("Woops, that's not what a cow says...")

keyPos = keyPosition(dictionary, "cow")
print("Cow is in the", keyPos, "position, lets put a fox there instead...
")
dictionary = replaceKey(dictionary, keyPos, "fox")

for x in dictionary:
    print("A", x, "goes", dictionary[x])

输出:

A cat goes meow
A dog goes woof
A cow goes ding ding ding
A goat goes beh
There are 4 animals in this list.

Woops, that's not what a cow says...
Cow is in the 2 position, lets put a fox there instead...

A cat goes meow
A dog goes woof
A fox goes ding ding ding
A goat goes beh

解决方案 17:

您可以将相同的值与多个键关联,或者仅删除一个键并重新添加具有相同值的新键。

例如,如果您有键->值:

red->1
blue->2
green->4

没有理由你不能添加purple->2或删除red->1并添加orange->1

解决方案 18:

如果有人想替换多级字典中所有出现的键,则方法。

函数检查字典中是否有特定的键,然后遍历子字典并递归调用该函数:

def update_keys(old_key,new_key,d):
    if isinstance(d,dict):
        if old_key in d:
            d[new_key] = d[old_key]
            del d[old_key]
        for key in d:
            updateKey(old_key,new_key,d[key])

update_keys('old','new',dictionary)

解决方案 19:

完整解决方案示例

声明一个包含所需映射的 json 文件

{
  "old_key_name": "new_key_name",
  "old_key_name_2": "new_key_name_2",
}

加载

with open("<filepath>") as json_file:
    format_dict = json.load(json_file)

创建此函数来使用你的映射来格式化字典

def format_output(dict_to_format,format_dict):
  for row in dict_to_format:
    if row in format_dict.keys() and row != format_dict[row]:
      dict_to_format[format_dict[row]] = dict_to_format.pop(row)
  return dict_to_format

解决方案 20:

我在下面写了这个函数,您可以在其中将当前键名更改为新键名。

def change_dictionary_key_name(dict_object, old_name, new_name):
    '''
    [PARAMETERS]: 
        dict_object (dict): The object of the dictionary to perform the change
        old_name (string): The original name of the key to be changed
        new_name (string): The new name of the key
    [RETURNS]:
        final_obj: The dictionary with the updated key names
    Take the dictionary and convert its keys to a list.
    Update the list with the new value and then convert the list of the new keys to 
    a new dictionary
    '''
    keys_list = list(dict_object.keys())
    for i in range(len(keys_list)):
        if (keys_list[i] == old_name):
            keys_list[i] = new_name

    final_obj = dict(zip(keys_list, list(dict_object.values()))) 
    return final_obj

假设一个 JSON,您可以通过以下行调用它并重命名它:

data = json.load(json_file)
for item in data:
    item = change_dictionary_key_name(item, old_key_name, new_key_name)

此处可以找到从列表到字典键的转换:
https://www.geeksforgeeks.org/python-ways-to-change-keys-in-dictionary/

解决方案 21:

有了熊猫,你就可以拥有这样的东西,

from pandas import DataFrame
df = DataFrame([{"fruit":"apple", "colour":"red"}])
df.rename(columns = {'fruit':'fruit_name'}, inplace = True)
df.to_dict('records')[0]
>>> {'fruit_name': 'apple', 'colour': 'red'}

解决方案 22:

  • 我将密钥存储在列表中(col_names

  • 使用此列表我更新了 data_dict 中存在的所有键

data_dict = { key:value for key, value in zip(col_names,list(data_dict.values()))  } 

解决方案 23:

替换字典中某些键的名称。保持字典中键、值对的原始顺序,而不创建新字典:

在此示例中,我们替换字典 d 中三个键中的两个键的名称。我们希望将键名称“x”替换为“a”,将键名称“y”替换为“b”。我们希望保持字典的原始顺序,而不创建新字典。

注意:我们无法迭代字典 d,因为我们正在对字典 d 进行更改,因此我们将迭代 d.copy()

单向:获取键、值。删除键、值对。添加新的键、值对。保持不变(无变化)。

# Original dictionary:  
d = {'x': 1, 'y': 2, 'z': 3}
# Conversion dictionary: 
d1 = {'x': 'a', 'y': 'b'}

# Run through all the key,value pairs in copy of the 
# dictionary d. 

for key,value in d.copy().items():
    if key in d1.keys():        
        # We get the name of the new_key value from the dictionary d1 with key.
        new_key = d1[key]       
else: 
    # No change to the name of the key
    new_key = key

# If there is no change to the name of the key, we must 
# delete the old key,value pair before creating 
# the new key,value pair.
del d[key]

# The new key,value pair goes to the end of the dictionary.
d[new_key] = value

输出:d = {'a': 1, 'b': 2, 'z': 3}

另一种方法:使用dictionary.pop(key)创建新的键值对并删除旧的键值对。

d = {'x': 1, 'y': 2, 'z': 3}
d1 = {'x': 'a', 'y': 'b'}

for key in d.copy().keys(): 
    if key in d1.keys():
        new_key = d1[key]
        d[new_key] = d.pop(key)
    else:
        # We need to do this if we want to keep 
        #the order of the dictionary.
        d[key] = d.pop(key)

输出:d = {'a': 1, 'b': 2, 'z': 3}

解决方案 24:

为了有效地保持顺序(另一种情况很简单,删除旧的并添加新的),避免有序字典需要重建(至少是部分重建),我整理了一个类(OrderedDictX),它扩展了 OrderedDict,并允许您高效地进行键更改,即复杂度为 O(1)。该实现也可以针对现在有序的内置字典类进行调整。

它使用 2 个额外的字典将更改的键(“外部” - 即它们对用户外部显示)重新映射到底层 OrderedDict 中的键(“内部”) - 字典将只保存已更改的键,因此只要没有进行任何键更改,它们就会为空。

性能测量:

import timeit
import random

# Efficiency tests
from collections import MutableMapping

class OrderedDictRaymond(dict, MutableMapping):
    def __init__(self, *args, **kwds):
        if len(args) > 1:
            raise TypeError('expected at 1 argument, got %d', len(args))
        if not hasattr(self, '_keys'):
            self._keys = []
        self.update(*args, **kwds)

    def rename(self,key,new_key):
        ind = self._keys.index(key)  #get the index of old key, O(N) operation
        self._keys[ind] = new_key    #replace old key with new key in self._keys
        self[new_key] = self[key]    #add the new key, this is added at the end of self._keys
        self._keys.pop(-1)           #pop the last item in self._keys
        dict.__delitem__(self, key)

    def clear(self):
        del self._keys[:]
        dict.clear(self)

    def __setitem__(self, key, value):
        if key not in self:
            self._keys.append(key)
        dict.__setitem__(self, key, value)

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        self._keys.remove(key)

    def __iter__(self):
        return iter(self._keys)

    def __reversed__(self):
        return reversed(self._keys)

    def popitem(self):
        if not self:
            raise KeyError
        key = self._keys.pop()
        value = dict.pop(self, key)
        return key, value

    def __reduce__(self):
        items = [[k, self[k]] for k in self]
        inst_dict = vars(self).copy()
        inst_dict.pop('_keys', None)
        return (self.__class__, (items,), inst_dict)

    setdefault = MutableMapping.setdefault
    update = MutableMapping.update
    pop = MutableMapping.pop
    keys = MutableMapping.keys
    values = MutableMapping.values
    items = MutableMapping.items

    def __repr__(self):
        pairs = ', '.join(map('%r: %r'.__mod__, self.items()))
        return '%s({%s})' % (self.__class__.__name__, pairs)

    def copy(self):
        return self.__class__(self)

    @classmethod
    def fromkeys(cls, iterable, value=None):
        d = cls()
        for key in iterable:
            d[key] = value
        return d

class obj_container:
    def __init__(self, obj) -> None:
        self.obj = obj

def change_key_splice(container, k_old, k_new):
    od = container.obj
    container.obj = OrderedDict((k_new if k == k_old else k, v) for k, v in od.items())

def change_key_raymond(container, k_old, k_new):
    od = container.obj
    od.rename(k_old, k_new)

def change_key_odx(container, k_old, k_new):
    odx = container.obj
    odx.change_key(k_old, k_new)

NUM_ITEMS = 20000
od_splice = OrderedDict([(x, x) for x in range(NUM_ITEMS)])
od_raymond = OrderedDictRaymond(od_splice.items())
odx = OrderedDictX(od_splice.items())
od_splice, od_raymond, odx = [obj_container(d) for d in [od_splice, od_raymond, odx]]
assert odx.obj == od_splice.obj
assert odx.obj == od_raymond.obj
# Pick randomly half of the keys to change
keys_to_change = random.sample(range(NUM_ITEMS), NUM_ITEMS//2)
print(f'OrderedDictX: {timeit.timeit(lambda: [change_key_odx(odx, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
print(f'OrderedDictRaymond: {timeit.timeit(lambda: [change_key_raymond(od_raymond, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
print(f'Splice: {timeit.timeit(lambda: [change_key_splice(od_splice, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
assert odx.obj == od_splice.obj
assert odx.obj == od_raymond.obj

结果:

OrderedDictX: 0.06587849999999995
OrderedDictRaymond: 1.1131364
Splice: 1165.2614647

正如预期的那样,拼接方法非常慢(虽然也没有想到会慢那么多)并且占用大量内存,而 O(N)Raymond 解决方案也更慢,在这个例子中是17倍。

当然,这个解决方案是 O(1),与 O(N)OrderedDictRaymond相比,随着字典大小的增加,时间差异变得更加明显,例如,对于 5 倍以上的元素(100000),O(N)现在慢了100 倍

NUM_ITEMS = 100000
OrderedDictX: 0.3636919999999999
OrderedDictRaymond: 36.3963971

这是代码,如果您发现问题或提出改进建议,请发表评论,因为这仍然可能容易出错。

from collections import OrderedDict


class OrderedDictX(OrderedDict):
    def __init__(self, *args, **kwargs):
        # Mappings from new->old (ext2int), old->new (int2ext).
        # Only the keys that are changed (internal key doesn't match what the user sees) are contained.
        self._keys_ext2int = {}
        self._keys_int2ext = {}
        self.update(*args, **kwargs)

    def change_key(self, k_old, k_new):
        # Validate that the old key is part of the dict
        if not self.__contains__(k_old):
            raise Exception(f'Cannot rename key {k_old} to {k_new}: {k_old} not existing in dict')

        # Return if no changing is actually to be done
        if len(dict.fromkeys([k_old, k_new])) == 1:
            return

        # Validate that the new key would not conflict with another one
        if self.__contains__(k_new):
            raise Exception(f'Cannot rename key {k_old} to {k_new}: {k_new} already in dict')

        # Preprocessing if key was already changed before
        if k_old in self._keys_ext2int:
            # Revert old change temporarily
            k_old_int = self._keys_ext2int[k_old]
            del self._keys_ext2int[k_old]
            k_old = k_old_int
            # Completely revert key-change and return if new key matches the internal key
            if len(dict.fromkeys([k_old, k_new])) == 1:
                del self._keys_int2ext[k_old]
                return

        # Finalize key change
        self._keys_ext2int[k_new] = k_old
        self._keys_int2ext[k_old] = k_new

    def change_keys_multiple(self, rename_map: dict):
        # For chaining changes: k1->k2, k2->k3, ..., kn->k_last
        # we change backwards when k_last is not present;
        # when k_last is k1 instead (circularity) we do almost the same
        # except that we first change kn to a non-present key k_non_p,
        # then after all the changes we can do the final change k_non_p->k1
        already_changed, k_non_p = {}, None
        for k_old, k_new in rename_map.items():
            # If key was already changed due to chaining changes, we may advance
            if k_old in already_changed:
                continue

            # If change is not chaining, directly change it
            if k_new not in self:
                self.change_key(k_old, k_new)
            else:
                # Change is chaining, find chain of changes
                change_chain, is_circular = OrderedDict([(k_old, k_new)]), False
                while True:
                    k_tail = next(iter(reversed(change_chain.values())))
                    # Chain ends if the tail key is no longer present or we detect circularity
                    if k_tail not in self:
                        break
                    if k_tail == k_old:
                        is_circular = True
                        break
                    # Continue chain
                    k_tail_new = rename_map[k_tail]
                    change_chain[k_tail] = k_tail_new
                    # Check for chain validity
                    if k_tail_new != k_old and k_tail_new in change_chain:
                        change_chain_str = ', '.join([f'{k1}->{k2}' for k1, k2 in change_chain.items()])
                        raise Exception(f'Invalid key-change chain detected: {change_chain_str}')

                # NOP change (k->k) if length of chain is 1
                if len(change_chain) == 1:
                    continue

                # Circularity trick: first we change the last key to a generated non-present one
                if is_circular:
                    if k_non_p is None:
                        k_non_p = self._get_non_present_key()
                    change_chain[next(iter(reversed(change_chain)))] = k_non_p

                # Apply change chain in reverse
                for k_old_chain, k_new_chain in reversed(change_chain.items()):
                    self.change_key(k_old_chain, k_new_chain)
                    already_changed[k_old_chain] = None

                # Circularity trick: do the final rename
                if is_circular:
                    self.change_key(k_non_p, k_old)

    def _get_non_present_key(self):
        i = len(self)
        while i in self:
            i -= 1
        return i

    def __contains__(self, k):
        return (super().__contains__(k) and k not in self._keys_int2ext) or k in self._keys_ext2int

    def __getitem__(self, k):
        if not self.__contains__(k):
            # Intentionally raise KeyError in ext2int
            return self._keys_ext2int[k]
        return super().__getitem__(self._keys_ext2int.get(k, k))

    def __setitem__(self, k, v):
        if k in self._keys_ext2int:
            return super().__setitem__(self._keys_ext2int[k], v)
        # If the key exists in the internal state but was renamed to a k_ext,
        # employ this trick: make it such that it appears as if k_ext has also been renamed to k
        if k in self._keys_int2ext:
            k_ext = self._keys_int2ext[k]
            self._keys_ext2int[k] = k_ext
            k = k_ext
        return super().__setitem__(k, v)

    def __delitem__(self, k):
        if not self.__contains__(k):
            # Intentionally raise KeyError in ext2int
            del self._keys_ext2int[k]
        if k in self._keys_ext2int:
            k_int = self._keys_ext2int[k]
            del self._keys_ext2int[k]
            del self._keys_int2ext[k_int]
            k = k_int
        return super().__delitem__(k)

    def __iter__(self):
        return self.keys()

    def __reversed__(self):
        for k in reversed(super().keys()):
            yield self._keys_int2ext.get(k, k)

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, dict):
            return False
        if len(self) != len(other):
            return False
        for (k, v), (k_other, v_other) in zip(self.items(), other.items()):
            if k != k_other or v != v_other:
                return False
        return True

    def get(self, k, default=None):
        return self.__getitem__(k) if self.__contains__(k) else default

    def popitem(self, last=True) -> tuple:
        if not last:
            k = next(iter(super().keys()))
        else:
            k = next(reversed(super().keys()))
        v = super().__getitem__(k)
        k = self._keys_int2ext.get(k, k)
        self.__delitem__(k)
        return k, v

    class OrderedDictXKeysView:
        def __init__(self, odx: 'OrderedDictX', orig_keys):
            self._int2ext = odx._keys_int2ext
            self._it = iter(orig_keys)
            self._it_rev = reversed(orig_keys)

        def __iter__(self):
            return self

        def __next__(self):
            k = self._it.__next__()
            return self._int2ext.get(k, k)

        def __reversed__(self):
            for k in self._it_rev:
                yield self._int2ext.get(k, k)

    class OrderedDictXItemsView:
        def __init__(self, odx: 'OrderedDictX', orig_items):
            self._int2ext = odx._keys_int2ext
            self._it = iter(orig_items)
            self._it_rev = reversed(orig_items)

        def __iter__(self):
            return self

        def __next__(self):
            k, v = self._it.__next__()
            return self._int2ext.get(k, k), v

        def __reversed__(self):
            for k, v in self._it_rev:
                yield self._int2ext.get(k, k), v

    def keys(self):
        return self.OrderedDictXKeysView(self, super().keys())

    def items(self):
        return self.OrderedDictXItemsView(self, super().items())

    def copy(self):
        return OrderedDictX(self.items())


# FIXME: move this to pytest
if __name__ == '__main__':
    MAX = 25
    items = [(i+1, i+1) for i in range(MAX)]
    keys = [i[0] for i in items]
    d = OrderedDictX(items)

    # keys() before change
    print(list(d.items()))
    assert list(d.keys()) == keys
    # __contains__ before change
    assert 1 in d
    # __getitem__ before change
    assert d[1] == 1
    # __setitem__ before change
    d[1] = 100
    assert d[1] == 100
    d[1] = 1
    assert d[1] == 1
    # __delitem__ before change
    assert MAX in d
    del d[MAX]
    assert MAX not in d
    d[MAX] = MAX
    assert MAX in d
    print('== Tests before key change finished ==')

    # change_key and __contains__
    assert MAX-1 in d
    assert MAX*2 not in d
    d.change_key(MAX-1, MAX*2)
    assert MAX-1 not in d
    assert MAX*2 in d
    # items() and keys()
    items[MAX-2] = (MAX*2, MAX-1)
    keys[MAX-2] = MAX*2
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    print(list(d.items()))
    # __getitem__
    assert d[MAX*2] == MAX-1
    # __setitem__
    d[MAX*2] = MAX*3
    items[MAX-2] = (MAX*2, MAX*3)
    keys[MAX-2] = MAX*2
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    # __delitem__
    del d[MAX]
    items = items[:-1]
    keys = keys[:-1]
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    d[MAX] = MAX
    items.append((MAX, MAX))
    keys.append(MAX)
    # __iter__
    assert list(d) == keys
    # __reversed__
    print(list(reversed(d.items())))
    assert list(reversed(d)) == list(reversed(keys))
    assert list(reversed(d.keys())) == list(reversed(keys))
    assert list(reversed(d.items())) == list(reversed(items))
    # pop_item()
    assert d.popitem() == (MAX, MAX)
    assert d.popitem() == (MAX*2, MAX*3)
    items = items[:-2]
    keys = keys[:-2]
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    # update()
    d.update({1: 1000, MAX-2: MAX*4})
    items[0] = (1, 1000)
    items[MAX-3] = (MAX-2, MAX*4)
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    # move_to_end()
    d.move_to_end(1)
    items = items[1:] + [items[0]]
    keys = keys[1:] + [keys[0]]
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    assert list(d) == keys
    # __eq__
    d.change_key(1, 2000)
    other_d = OrderedDictX(d.items())
    assert d == other_d
    assert other_d == d

    import timeit
    import random

    # Efficiency tests
    from collections import MutableMapping

    class OrderedDictRaymond(dict, MutableMapping):
        def __init__(self, *args, **kwds):
            if len(args) > 1:
                raise TypeError('expected at 1 argument, got %d', len(args))
            if not hasattr(self, '_keys'):
                self._keys = []
            self.update(*args, **kwds)

        def rename(self,key,new_key):
            ind = self._keys.index(key)  #get the index of old key, O(N) operation
            self._keys[ind] = new_key    #replace old key with new key in self._keys
            self[new_key] = self[key]    #add the new key, this is added at the end of self._keys
            self._keys.pop(-1)           #pop the last item in self._keys
            dict.__delitem__(self, key)

        def clear(self):
            del self._keys[:]
            dict.clear(self)

        def __setitem__(self, key, value):
            if key not in self:
                self._keys.append(key)
            dict.__setitem__(self, key, value)

        def __delitem__(self, key):
            dict.__delitem__(self, key)
            self._keys.remove(key)

        def __iter__(self):
            return iter(self._keys)

        def __reversed__(self):
            return reversed(self._keys)

        def popitem(self):
            if not self:
                raise KeyError
            key = self._keys.pop()
            value = dict.pop(self, key)
            return key, value

        def __reduce__(self):
            items = [[k, self[k]] for k in self]
            inst_dict = vars(self).copy()
            inst_dict.pop('_keys', None)
            return (self.__class__, (items,), inst_dict)

        setdefault = MutableMapping.setdefault
        update = MutableMapping.update
        pop = MutableMapping.pop
        keys = MutableMapping.keys
        values = MutableMapping.values
        items = MutableMapping.items

        def __repr__(self):
            pairs = ', '.join(map('%r: %r'.__mod__, self.items()))
            return '%s({%s})' % (self.__class__.__name__, pairs)

        def copy(self):
            return self.__class__(self)

        @classmethod
        def fromkeys(cls, iterable, value=None):
            d = cls()
            for key in iterable:
                d[key] = value
            return d

    class obj_container:
        def __init__(self, obj) -> None:
            self.obj = obj

    def change_key_splice(container, k_old, k_new):
        od = container.obj
        container.obj = OrderedDict((k_new if k == k_old else k, v) for k, v in od.items())

    def change_key_raymond(container, k_old, k_new):
        od = container.obj
        od.rename(k_old, k_new)

    def change_key_odx(container, k_old, k_new):
        odx = container.obj
        odx.change_key(k_old, k_new)

    NUM_ITEMS = 100000
    od_splice = OrderedDict([(x, x) for x in range(NUM_ITEMS)])
    od_raymond = OrderedDictRaymond(od_splice.items())
    odx = OrderedDictX(od_splice.items())
    od_splice, od_raymond, odx = [obj_container(d) for d in [od_splice, od_raymond, odx]]
    assert odx.obj == od_splice.obj
    assert odx.obj == od_raymond.obj
    # Pick randomly half of the keys to change
    keys_to_change = random.sample(range(NUM_ITEMS), NUM_ITEMS//2)
    print(f'OrderedDictX: {timeit.timeit(lambda: [change_key_odx(odx, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
    #print(f'OrderedDictRaymond: {timeit.timeit(lambda: [change_key_raymond(od_raymond, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
    #print(f'Splice: {timeit.timeit(lambda: [change_key_splice(od_splice, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
    # assert odx.obj == od_splice.obj
    # assert odx.obj == od_raymond.obj
    keys_odx = list(odx.obj)
    keys_raymond = list(od_raymond.obj)
    keys_splice = list(od_splice.obj)
    print('== items() ==')
    print(f'OrderedDictX: {timeit.timeit(lambda: [(k, v) for k, v in odx.obj.items()], number=1)}')
    print(f'OrderedDictRaymond: {timeit.timeit(lambda: [(k, v) for k, v in od_raymond.obj.items()], number=1)}')
    print(f'OrderedDict: {timeit.timeit(lambda: [(k, v) for k, v in od_splice.obj.items()], number=1)}')
    print('== keys() ==')
    print(f'OrderedDictX: {timeit.timeit(lambda: [k for k in odx.obj.keys()], number=1)}')
    print(f'OrderedDictRaymond: {timeit.timeit(lambda: [k for k in od_raymond.obj.keys()], number=1)}')
    print(f'OrderedDict: {timeit.timeit(lambda: [k for k in od_splice.obj.keys()], number=1)}')
    print('== list() ==')
    print(f'OrderedDictX: {timeit.timeit(lambda: list(odx.obj), number=1)}')
    print(f'OrderedDictRaymond: {timeit.timeit(lambda: list(od_raymond.obj), number=1)}')
    print(f'OrderedDict: {timeit.timeit(lambda: list(od_splice.obj), number=1)}')
    print('== in ==')
    print(f'OrderedDictX: {timeit.timeit(lambda: [k in odx.obj for k in keys_odx], number=1)}')
    print(f'OrderedDictRaymond: {timeit.timeit(lambda: [k in od_raymond.obj for k in keys_raymond], number=1)}')
    print(f'OrderedDict: {timeit.timeit(lambda: [k in od_splice.obj for k in keys_splice], number=1)}')
    print('== get ==')
    print(f'OrderedDictX: {timeit.timeit(lambda: [odx.obj[k] for k in keys_odx], number=1)}')
    print(f'OrderedDictRaymond: {timeit.timeit(lambda: [od_raymond.obj[k] for k in keys_raymond], number=1)}')
    print(f'OrderedDict: {timeit.timeit(lambda: [od_splice.obj[k] for k in keys_splice], number=1)}')

解决方案 25:

我还没有看到这个确切的答案:

dict['key'] = value

你甚至可以对对象属性执行此操作。通过执行以下操作将它们放入字典中:

dict = vars(obj)

然后,您可以像操作字典一样操作对象属性:

dict['attribute'] = value
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用