Change/update the key of an object dictionary in python

I have an object class that I use as a key into a python dictionary.

from dataclasses import dataclass


@dataclass
class CompWord:
    c: str
    length: int

    def __hash__(self):
        return hash(self.c)

    def __eq__(self, other):
        return self.c == other


_ = lambda: defaultdict(_)
d = _()
for compword1 in [CompWord('a', 1), CompWord('b', 2)]:
    key = d[compword1]
    for compword2 in [CompWord('c', 1), CompWord('d', 2)]:
        key = key[compword2]

at this point, d is

CompWord(c='a', length=1)
        CompWord(c='c', length=1)
                CompWord(c='d', length=2)
CompWord(c='b', length=2)
        CompWord(c='c', length=1)
                CompWord(c='d', length=2)

I want to update the key in this dictionary if I come across it again only if the length of CompWord is greater than length of key that is already in the dictionary. For example, CompWord(a, 4) > CompWord(a, 1), so I want to update this key with CompWord(a, 4), while also preserving the nested dictionaries under CompWord(a, 1).

Expected output after I update CompWord(a, 1) to Compword(a, 4)

c_word = CompWord('a', 4)
if c_word in d:
    # update d[c_word] with new key CompWord(c_word.length, <old length 1>)
CompWord(c='a', length=4)
        CompWord(c='c', length=1)
                CompWord(c='d', length=2)
CompWord(c='b', length=2)
        CompWord(c='c', length=1)
                CompWord(c='d', length=2)

I need to able to reference the length of the old key above which is 1, but I am not sure how I get access to it.

Answer

You’ve edited your post a bunch since I started writing my answer, and I don’t really feel like reading through your post again…

I’d suggest implementing __lt__ and using max():

@dataclass
class CompWord:
    c: str
    length: int
    def __hash__(self):
        return hash(self.c)

    def __eq__(self, other):
        return self.c == other

    def __lt__(self, other):
        return self.length < other.length

Now accumulate keys to replace:

keys_to_replace = []
for key in d:
    if key == c_word:
        keys_to_replace.append((key, max(key, c_word)))

Now replace keys:

for old_key, new_key in keys_to_replace:
    d[new_key] = d.pop(old_key)

Also, I’d recommend returning self.c == other.c in your __eq__ as that is more explicit.

EDIT:

I suggest implementing a recursive key_replacer() function if you want to drill down into a deeply nested dictionary, as your edits suggest.

I also think it might not be a good idea to __hash__ and __eq__ on only one of the values of your dataclass. That seems like a recipe for headaches during debugging.