1

I was testing the idea of using @property in OOP:

class Person(object):
    @property
    def name(self):
        return self.name

    @name.setter
    def name(self, newname):
        self.name = newname

james = Person()
james.name = 'James Bond'
print(james.name)
>>> RecursionError: maximum recursion depth exceeded

Somehow this gives me an Error for recursion??

but if I change self.name to self._name, it seems to solve the problem. So I guess I can not set a self.name while I am using name() as a @property?

jxie0755
  • 1,682
  • 1
  • 16
  • 35

2 Answers2

3

The reason for the error is that you are attempting to return an attribute with exactly the same name as the method being decorated by property. Thus, when you call the method name, the call triggers the method again, because self.name is the method declared in the class. This triggers the non-terminating recursion. Instead, change the attribute name:

class Person(object):
   @property
   def name(self):
     return self._name

   @name.setter
   def name(self, newname):
      self._name = newname
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • So the way I found, which is to add `'_'`, is a proper way to do this? – jxie0755 Jan 27 '18 at 02:02
  • @Code_Control_jxie0755 in this case, all you need to do is change the variable name. Generally, `_variablename` is used in most demonstrations of `property`. – Ajax1234 Jan 27 '18 at 02:03
  • 1
    Another way is to use `self.__dict__['name']`, which is a little more arcane but a very cool way to hide property values. – Mad Physicist Jan 27 '18 at 02:14
0

Also, you can create the internal proxy object if you think that _ notation is ugly (example for python 3.3+):

import types

class Person(object):
   def __init__(self):
       self.me = types.SimpleNamespace(name = "")

   @property
   def name(self):
     return self.me.name

   @name.setter
   def name(self, newname):
      self.me.name = newname
Stanislav Ivanov
  • 1,854
  • 1
  • 16
  • 22
  • You don't really eliminate what to me is the main ugliness of `_`, which is that you create another attribute for the user to modify. – Mad Physicist Jan 27 '18 at 02:41
  • Maybe little magic with class decorator will protect the variable against overriding: https://stackoverflow.com/a/39716001/4265407 but not from field access and manipulation. I think we need something like `inspect` to do it. – Stanislav Ivanov Jan 27 '18 at 02:54
  • As I suggested for the other answer, `self.__dict__['name']` goes a long way to hiding the attribute by harnessing the precedence of data attributes on the class over instance dict entries. – Mad Physicist Jan 27 '18 at 03:03
  • But if I wrote `s.__dict__['name'] = "foo"` I can write `s.name = "bar"` after. Given the fact that many critical variables usually defined/assigned in the class constructor... – Stanislav Ivanov Jan 27 '18 at 03:21