0

is this possible? I want to assign a value to a custom dictionary using <class_name>.<attribute_name> syntax.

here's an example:

class Foo:
    def __init__(self):
        self.__values__ = {}
    def add_a_value_using_dot_syntax(self, index, value): # what should this be?
        self.__values__[index] = value

bar = Foo()
bar.baz = 'hello'

print(bar.baz) # hello
print(bar.__values__) # {'baz': 'hello'}

I know that this can be done with bracket syntax by overriding __setitem__ but it doesn't seem to work for dot syntax..

Thanks

  • can you please elaborate on exactly what you want to do? – juanpa.arrivillaga Sep 12 '22 at 18:36
  • You can put whatever code you want in a getter and setter; can you clarify what information you need that is not already answered in [this post](https://stackoverflow.com/a/2627034/6273251)? – Random Davis Sep 12 '22 at 18:42
  • Please show an [mcve] to illustrate what you are trying to do. This can even be pseudocode or not entirely correct python as long as you make it clear which parts you are guessing at and want to do. – Code-Apprentice Sep 12 '22 at 18:42
  • In a class method, you can do `self.foobar = "baz"`. This is the same as you already do in `__init__()`. – Code-Apprentice Sep 12 '22 at 18:43
  • yes but i want to assign arbitrary attributes to the class and somehow have them stored in a dictionary other than `__dict__` (`__values__` in the example). I did this with `__setitem__` already but it doesn't work for dot syntax, only bracket syntax. –  Sep 12 '22 at 18:45
  • https://stackoverflow.com/questions/2352181/how-to-use-a-dot-to-access-members-of-dictionary – Nemo Sep 12 '22 at 18:53

3 Answers3

0

You can override __getattribute__/__getattr__/__setattr__/__delattr__ to do what you want.

However, you should be very careful when doing so. A lot of code will make assumptions about the attributes of your objects, and it is very easy to break standard data model contracts in a way that makes your class unusable in certain contexts.

0x5453
  • 12,753
  • 1
  • 32
  • 61
0

Use __setattr__ instead of __setitem__. This method is always called, so you'll want some logic that decides what to do based on the value of the attribute being assigned to.

class Foo:
    def __init__(self):
        self._values = {}  # Do not invent new dunder names

    def __setattr__(self, name, value):
        if name in ["baz", "v1", "v2"]:  # e.g.
            self._values['name'] = value
        else:
            # Assign to name "normally"
            super().__setattr__(name, value)
chepner
  • 497,756
  • 71
  • 530
  • 681
0

You'd need to override __getattr__ and __setattr__, but since these are fundamental to how the class works, you'd need some extra logic, and there's an enormous minefield of potentially undefined behavior. I think you'd want

class Foo:
    def __init__(self):
        self.__values__ = {}
        super().__init__()

    def __setattr__(self, name, value):
        if name == '__values__':
            self.__dict__['__values__'] = value
            return
        try:
            self.__getattr__(name)
        except AttributeError:
            self.__values__[name] = value
        return super().__setattr__(name, value)

    def __getattr__(self, name):
        if name == '__values__':
            return self.__dict__['values']
        try:
            return super().__getattr__(name)
        except AttributeError:
            try:
                return self.__values__[name]
            except KeyError:
                raise AttributeError

This is extremely evil/cursed, and should never be done.