3

I'm trying to read in a bunch of data from text files to a dictionary, and I've made a couple of small typos which end up creating new key/value pairs and breaking the program (which can be annoying and a pain to debug).

This got me wondering if there is a way to create a dictionary to which no keys can be added or removed after the initial declaration. This strikes me as something that must exist but I can't find an example of it; does anyone know of something that would fit the bill?

def change_key(dictionary, key, new_value):
    a = dictionary.__len__()
    dictionary[key] = new_value
    if dictionary.__len__() != a:
        raise ValueError("new key added")

What I'm looking for is a more elegant implementation of the code above that is:

  1. not a massive mess of code

  2. capable of dealing with things like appending to a nested list or adding to a nested dict

  3. reasonably efficient

Pioneer_11
  • 670
  • 4
  • 19
  • 1
    You could create a Function with predefined Keys which just alters the Values inside the Dictionary checking before Insertion if the Key exists – jack Jul 19 '22 at 10:59
  • What would be inmutable keys? Do you mean that you cannot remove or add keys? – Dani Mesejo Jul 19 '22 at 11:07
  • @DaniMesejo yes – Pioneer_11 Jul 19 '22 at 11:09
  • How does an inmutable dict solves your issue? Perhaps you can add a code example to better understand the problem – Dani Mesejo Jul 19 '22 at 11:12
  • Maybe fuzzy string matching could be an option for ignoring typos etc. – L_W Jul 19 '22 at 11:15
  • @DaniMesejo rather than having to dig through the program to find the line where I misspelled a key there would be a nice easy error log showing me where and when I did it. – Pioneer_11 Jul 19 '22 at 11:15
  • I'm using this in a relatively big program and the values have to be read, re-assigned and altered a bunch so it can be a pain to track down bugs – Pioneer_11 Jul 19 '22 at 11:18
  • Why you say that the solution in the link `didn't completely prevent alteration`? – Dani Mesejo Jul 19 '22 at 11:27
  • @LW it would work but it seems unnecessarily complicated – Pioneer_11 Jul 19 '22 at 11:27
  • 1
    *"if there is a way to create a dictionary with immutable keys but mutable values"* - that's exactly what a dict already is... – Tomerikoo Jul 19 '22 at 12:46
  • I've personally disliked the comments that were added as they just served to add more fuel to a raging fire; point being, the question is already sufficiently confusing as it stands. Even after re-reading it the first time, I *still* have **no idea** what the question is asking. Please update the question above to clarify better on the specific problem you're having, and how you would like to resolve it; I would personally illustrate with a code example to convey this a bit more clearly. – rv.kvetch Jul 19 '22 at 14:38
  • @Tomerikoo apologies I meant where the ```__dict__``` is immutable. e.g. you cannot add or remove keys. I have corrected the question – Pioneer_11 Jul 19 '22 at 15:04
  • @AdamLadd that is absolutely not what you mean -- `dict` objects **don't even have `__dict__`'s**. In any case, it sounds like you just want a custom class with `__slots__` – juanpa.arrivillaga Jul 19 '22 at 22:25
  • 1
    As an aside, you really shouldn't be doing `dictionary.__len__()` and instead just do `len(dictionary)` – juanpa.arrivillaga Jul 19 '22 at 22:25
  • @juanpa.arrivillaga apologies my understanding was that dicts were objects and all objects had ```__dict__```'s so I didn't think to check. I have corrected the question again – Pioneer_11 Jul 20 '22 at 10:16
  • Yes, dicts are objects, but not all objects have `__dict__`. User-defined objects will have a `__dict__` by default *unless* you define `__slots__` – juanpa.arrivillaga Jul 20 '22 at 16:21

1 Answers1

6

I believe what you're looking for is a dataclass with __slots__ method (In Python 3.10+, this can be achieved with @dataclass(slots=True)):

from dataclasses import dataclass, asdict


@dataclass
class FixedKeys:
    __slots__ = ("key_1", "key_2", "key_3")
    key_1: str
    key_2: str
    key_3: str


d = FixedKeys(key_1="something", key_2="something_else", key_3="another_thing")
d.key_1 = "updated_value"  # This will work fine
d.key_that_was_not_predefined = "some value"  # This will raise AttributeError
d = asdict(d)  # This converts a dataclass instance to a normal dictionary
Somebody Out There
  • 347
  • 1
  • 5
  • 15
  • 2
    this is good. the question was however not, but this is pretty rock solid, or at least getting there. good work, man! – rv.kvetch Jul 19 '22 at 14:43
  • Just a regular class will do just fine, and note, `HashMap` is a terrible name for a class that doesn't implement a hash map... – juanpa.arrivillaga Jul 19 '22 at 22:24
  • 1
    @juanpa.arrivillaga You probably wouldn't want to declare a normal class in situations where all you want is a structure to store some state, as that comes with [large amounts boilerplate dunder method code](https://stackoverflow.com/a/47955313/11010254) and requires even more code like a vars() call and a dictionary comprehension to convert to a normal dictionary. – Somebody Out There Jul 20 '22 at 09:36