EDIT This code contains several bugs, see jsbueno's answer below for a correct version I would like to create read-only attributes that dynamically retrieve values from an internal dictionary. I have tried to implement these as descriptors: from typing import Any class AttDesc: def __init__(self, name): self.name = name def __get__(self, obj, objtype=None): return obj._d[self.name] def __set__(self, obj, value): raise AtrributeError("Read only!") class A: def __init__(self, klist: list[str], vlist: list[Any]) -> None: self._d = dict(zip(klist, vlist)) for k in self._d: setattr(type(self), k, AttDesc(k)) @property def d(self): return self._d The problem with this approach is that the descriptor instances are class attributes. This means that, in an interactive session: a1 = A(['x', 'y'], [1, 2]) a2 = A(['z', ], [3]) if I press TAB for autocomplete on a1. I will be given the option to choose the attribute z, which "belongs" to instance a2. I have also tried to implement via the instance's __getattr__ method: class B: def __init__(self, klist: list[str], vlist: list[Any]): object.__setattr__(self, '_d', dict(zip(klist, vlist))) @property def d(self): return self._d def __getattr__(self, name): if name in self.d: return self.d[name] else: object.__getattr__(name) def __setattr__(self, k, v): if k in self.d: raise AttributeError("Read only!") object.__setattr__(self, k, v) If I try b = B(['w'], [3]) in an interactive session, pressing TAB on b. won't show w as an option, because it's not an instance attribute. Pandas does something similar to what I want: it allows accessing the columns of a DataFrame with the dot operator, and only the appropriate columns for a given instance show up upon pressing TAB in an interactive session. I have tried to look into the Pandas code but it is a bit abstruse to me. I think they use something similar to my second __getattr__ option, but I don't understand how they make it work. How could I implement this behaviour? Continue reading...