29

Here is a test class that I wrote to became familiar with @properties and setter functionality in Python script:

class Test(object):
    def __init__(self, value):
        self.x =  value
    @property
    def x(self):
        return self.x
    @x.setter
    def x(self, value):
        self.x = value

The problems is that when I want to create an object from my class, I face the following error:

>>> t = Test(1)

Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    t = Test(1)
  File "<pyshell#18>", line 3, in __init__
    self.x =  value
  File "<pyshell#18>", line 9, in x
    self.x = value
  File "<pyshell#18>", line 9, in x
  #A bunch of lines skipped
RuntimeError: maximum recursion depth exceeded
>>> 
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
EbraHim
  • 2,279
  • 2
  • 16
  • 28
  • 2
    Use `self._x` instead of `self.x` for private member. By naming both member and property `x` property shadows member, and `return self.x` in getter body calls itself. – Łukasz Rogalski Apr 29 '16 at 06:53

2 Answers2

50

You are using the same name for the getter, setter and attribute. When setting up a property, you must rename the attribute locally; the convention is to prefix it with an underscore.

class Test(object):
    def __init__(self, value):
        self._x =  value

    @property
    def x(self):
        return self._x
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
  • Thank you. Please take a look at _Byte Commander_'s answer [here](http://stackoverflow.com/questions/36929460/how-to-keep-variable-and-dictionary-that-contains-it-consistent/36930474?noredirect=1#comment61422678_36930474). He used same name for `setter`, `getter` and `variable`, but his program works fine. – EbraHim Apr 29 '16 at 07:02
  • 2
    If you've defined the setter method, it's better to only access the private variable `self._x` in the getter / setter / deleter methods. In \_\_init__ you can just say `self.x = value`. – Rob Apr 29 '16 at 07:02
  • @Rob I'm not sure that's correct. Why is it better? It's not a convention I'm aware of. – Peter Wood Apr 29 '16 at 07:12
  • 2
    You are implementing a setter methode for a reason, probably to do some input checking / manipulation. It makes sense to do the same thing during instantiation of the object. – Rob Apr 29 '16 at 07:16
  • 1
    Yes, exactly. Assigning to the private attribute in `__init__` will bypass the `property` `setter` method and therefore not apply the logic contained there, as @Rob said. It is probably buggy or at least inconsistent to allow potentially different values during instantiation and later one, during re-assignment. – Alex Povel Apr 29 '20 at 14:42
-3

The problem is in these lines:

def x(self):
    return self.x

Replace it with

def get_x(self):
    return self.x

Because now the function calls itself, leading to the recursion depth exceeded.

Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
Mathias711
  • 6,568
  • 4
  • 41
  • 58
  • I want to use `@properties`. – EbraHim Apr 29 '16 at 06:55
  • 1
    Using getters/setters is a Python antipattern. It's recommended to uses properties with the @property decorator. Read: https://www.pythonmorsels.com/customizing-what-happens-when-you-assign-attribute/ – Guzman Ojero May 16 '22 at 22:48