-1

I want to define a class like this:

class Test:
    _ID = itertools.count()

    def __init__(self):
        self.id = next(self._ID)
        self.__setattr__('_dict', {})


    def __getattr__(self, key):
        return self._dict[key]


    def __setattr__(self, key, value):
        self._dict[key] = value

What is the best approach in this case?

Jan Koval
  • 37
  • 1
  • 1
  • 4
  • What is this line supposed to do `self.__setattr__('_dict', {})`? – mapf May 06 '20 at 15:16
  • @mapf i used it to define dictionary inside the class to prevent from recursion with __setattr__. – Jan Koval May 06 '20 at 15:18
  • 1
    @JanKoval But you're calling `self.__setattr__` explicitly; that's driving straight at the problem you're trying to avoid. On the other hand, if you called the `__setattr__` in the `object` class instead, you would avoid the overridden method that causes the recursion. – khelwood May 06 '20 at 15:21
  • @khelwood so, what i need to change, to use something like this: test_object.a = 5 (a is the new key in dictionary) – Jan Koval May 06 '20 at 15:23
  • @JanKoval Hopefully the answer posted answers that. – khelwood May 06 '20 at 15:25
  • Python objects already have an optimised ``__dict__``. Why do you want to manually recreate this? – MisterMiyagi May 06 '20 at 15:39

1 Answers1

1

self.id = calls __setattr__ for id key. Inside __setattr__ you try to get self._dict which triggers __getattr__ since the key _dict is not yet defined and inside __getattr__ you try to do the same thing - get self._dict, so the __getattr__ is called again, and again... up to recursion limit.

Use super() to call the default __setattr_ method, so your __getattr__ implementation won't be to get self._dict:

class Test:
    _ID = itertools.count()

    def __init__(self):
        super().__setattr__("id", next(self._ID))
        super().__setattr__("_dict", {})

    def __getattr__(self, key):
        return self._dict[key]

    def __setattr__(self, key, value):
        self._dict[key] = value

RafalS
  • 5,834
  • 1
  • 20
  • 25