There is no Rename, but it is possible to store the value in a new key and delete the old one in a single operation if the method is used pop
of dictionaries:
RE2["Data de Nascimento"] = RE2.pop("Nascimento")
This saves a line, and the need for del
. In addition to the pop
allows you to place a default argument - so, if by chance the old key is not set, you will not have an error - instead, the default value is used:
RE2["Data de Nascimento"] = RE2.pop("Nascimento", "")
Will create the entrance "Data de Nascimento"
with the value ""
(empty string), if there was no key "Nascimento
" in the original dictionary.
If it’s an operation you’ll do often, it can be more elegant (but not always), create a class that extends the original Python dictionaries and add a method that does this. Internally, the best way will still be the use of pop
and creation of the new key - but your dictionary may have a "Rename" method that does this:
class MeuDict(dict):
def rename(self, old_key, new_key):
self[new_key] = self.pop(old_key)
And this can be used directly, if only its original object is of this new class. Since normal Python dictionaries accept dictionaries as parameters for initialization, a normal dictionary can be converted in this simple with:
RE2 = MeuDict(RE2)
and then:
RE2.rename("Nascimento", "Data de nascimento")
If you are going to use this code in "real" production, that is, you need something reliable, with more functionality, you can take advantage that the logic is all in one place, and make the code "thread safe" - that is, in the case of a program with several threads, make the Rename an operation "atomic" - with the use of a lock - this avoids a chance that the value being renamed is neither in one key nor in another at any given time.
We can also use the "Sentinel Pattern" to repeat in the method rename
the behaviour of the parameter default
of pop.
import threading
_sentinel = object()
class MeuDict(dict):
def __init__(self, *args, **kw):
self.lock = threading.Lock()
super().__init__(*args, **kw)
def rename(self, old_key, new_key, default=_sentinel):
pop_sentinel = {} if default is _sentinel else {'default': default}
with self.lock:
# cria a nova chave - entre essa linha e a próxima as
# duas chaves existem. Se a thread mudar bem nesse ponto, o valor
# vai ser encontrado nas duas - o que é melhor
# que "em nenhuma", que acontece com o `pop`
self[new_key] = self.get(old_key, **pop_sentinel)
del old_key
If an atomic operation is really necessary
After answering, I realized that the threading.Lock
alone only prevents the same lock from being used in another thread - there would still be the risk of in a second thread some code "look" the dictionary between the two key modifiements. That’s why I changed the code of pop
for copy + del - the two keys will exist at that transition time.
If you really need a thread-safe object that does not allow any race-condition in which the dictionary is "viewed" without any or without two keys, the only way is to increase class specialization - you have to create a "Mapping" (an object like a dictionary), which uses the thread Locking at all points where a dictionary item is to be consulted - then, using the same lock, it will have to wait for the end of the update before making the query available. In this case, it is not worth inheriting from a dictionary (Dict) - that because of internal optimizations, does not have a single point of reference of the keys and values, and yes, inherit from collections.abc.MutableMapping
, implement the rename
as above, and, dntro do __getitem__
, __iter__
and __delitem__
also make use of the same lock.
The biggest difference is that Collections.abc.Mutablemapping allows you to implement an object that works like a dictionary, but itself is not a dictionary - in the case of inheriting from dict
, manipulate the keys in the methods using the self
. In this other implementation, the recommendation is to keep an internal dictionary in a private attribute.
it was not necessary to explain so thoroughly as to have imported a library, but okay.
– user141036
For what you want, just removing one key and creating another is enough. Other people seeking the same question may have a scenario where they need atomic operation, or they want to understand how Python works from the inside.
– jsbueno