I am new to Python. So, please forgive me if this is a basic question. I researched this topic on the Internet and SO, but I couldn't find an explanation. I am using Anaconda 3.6 distribution.
I am trying to create a simple getter and setter for an attribute. I will walk you through the errors I get.
class Person:
def __init__(self,name):
self.name=name
bob = Person('Bob Smith')
print(bob.name)
This prints the first name I agree that I haven't overridden print
or getattribute
method. Also, there is no property here. This was to test whether the basic code works.
Let's modify the code to add property:
class Person:
def __init__(self,name):
self.name=name
@property
def name(self):
"name property docs"
print('fetch...')
return self.name
bob = Person('Bob Smith')
print(bob.name)
As soon as I write above code in PyCharm, I get a yellow bulb icon, stating that the variable must be private. I don't understand the rationale.
Ignoring above, if I run above code, I get:
Traceback (most recent call last): File "C:\..., in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-25-62e9a426d2a9>", line 2, in <module> bob = Person('Bob Smith') File "<ipython-input-24-6c55f4b7326f>", line 4, in __init__ self.name=name AttributeError: can't set attribute
Now, I researched this topic, and I found that there are two fixes (without knowing why this works):
Fix #1: Change the variable name
to _name
class Person:
def __init__(self,name):
self._name=name #Changed name to _name
@property
def name(self):
"name property docs"
print('fetch...')
return self._name #Changed name to _name
bob = Person('Bob Smith')
print(bob.name)
This works well in that it prints the output correctly.
Fix #2: Change property name to from name(self)
to _name(self)
and revert variable name from _name
to name
class Person:
def __init__(self,name):
self.name=name #changed to name
@property
def _name(self): #Changed to _name
"name property docs"
print('fetch...')
return self.name #changed to name
bob = Person('Bob Smith')
print(bob.name)
Now, this works prints as expected.
As a next step, I created setter
, getter
, and deleter
properties using decorators. They follow similar naming conventions as described above--i.e. either prefix _
to the variable name or the method name:
@_name.setter
def _name(self,value):
"name property setter"
print('change...')
self.name=value
@_name.deleter
def _name(self):
print('remove')
del self.name
bob = Person('Bob Smith')
print(bob.name)
bob.name = 'Bobby Smith'
print(bob.name)
del bob.name
Question: I am not really sure why Python 3.x is enforcing adding _
to variable name or method name.
As per Python property with public getter and private setter, What is the difference in python attributes with underscore in front and back, and https://www.python.org/dev/peps/pep-0008/#naming-conventions, an underscore prefix is a weak indicator to the user that this variable is a private variable, but there is no extra mechanism in place (by Python, similar to what Java does) to check or correct such behavior.
So, the big question at hand is that why is it that I need to have underscores for working with properties? I believe those underscore prefixes are just for users to know that this is a private variables.
I am using Lutz's book to learn Python, and above example is inspired from his book.