0

I'm using property() for setting up getters and setters for a Class
Here's the code:

class Person:

    def __init__(self, email=None):
        self.email = email

    def set_email(self, value):
        self._email = value

    def get_email(self):
        return self._email

    email = property(get_email, set_email)


if __name__ == "__main__":

    try:
        contact = Person(email="abc@123")
    except Exception as e:
        print(e)

This code work perfect, but, when I change self._email to self.email inside set_email() to this:

def set_email(self, value):
        self.email = value

I am getting:

self.email = value
[Previous line repeated 494 more times]
RecursionError: maximum recursion depth exceeded

I understand that a single underscore before a variable denotes that the variable is for internal use only.
But I can't understand why do I need to use self._email even though I have used self.email in the constructor.

Can anyone explain why is this happening?

saintlyzero
  • 1,632
  • 2
  • 18
  • 26
  • `self._email` and `self.email` are considered as different variables. *I understand that a single underscore before a variable denotes that the variable is for internal use only.* this is a wrong understanding. – shaik moeed Dec 11 '19 at 09:02
  • @shaikmoeed using a single leading underscore DOES denotes an implementation variable / attribute / property / method. – bruno desthuilliers Dec 11 '19 at 09:09
  • @brunodesthuilliers No, It's by convention developer use([link](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-a-single-and-a-double-underscore-before-an-object-name)). Can you please share any link which supports your statement? – shaik moeed Dec 11 '19 at 09:19
  • @shaikmoeed I didn't said there was any kind of privacy enforcement - Python has zero "privacy" - I said this naming "denoted" a name used for implementation and that _should not_ (not "could not") be used by client code. The fact that it's a convention instead of a strict enforcement does'nt change this semantic. Just like ALL_UPPER names denote (pseudo) constants - Python has no notion of symbolic constants either, yet an ALL_UPPER name means you _should_ not rebind this name nor mutate what it's bound to. – bruno desthuilliers Dec 11 '19 at 09:22
  • @brunodesthuilliers Thanks for explaining. My understanding from this is.., it means, here due to *property(get_email, set_email)*, `set_email` function is invoked when `self.email` was assigned value in the constructor and again assignment in the same function does leads it to recursion? Am I correct? – shaik moeed Dec 11 '19 at 09:40

1 Answers1

1

The assignment self.email = ... will first check whether email is a data-descriptor and if so, it will invoke the corresponding setter function, in your case this is set_email. So when you do self.email = ... then effectively set_email(self, ...) is invoked. Within __init__ this is not a problem, but within set_email this obviously leads to an infinite recursion.

a_guest
  • 34,165
  • 12
  • 64
  • 118