Для чего подчеркивания в @property?
Всех приветствую. Помогите, пожалуйста, разобраться. Вот код:
class Person:
def __init__(self):
self.age = 0
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("Age cannot be negative")
self.__age = value
t = Person()
t.age = 12
print(t.age) # 12
Он корректно работает, но меня смущает вот что: атрибут Person называется age, а геттеры и сеттеры взаимодействуют c __age. Я понимаю, что __ заменяется на имя класса и получается _Person__age. Собственно, в коде так и получается:
print(dir(t))
# ['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age']
При этом без дандеров я получаю ошибку:
class Person:
def __init__(self):
self.age = 0
@property
def age(self):
return self.age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("Age cannot be negative")
self.age = value
t = Person()
t.age = 12
print(t.age)
File "main.py", line 47, in age
if value < 0:
RecursionError: maximum recursion depth exceeded in comparison
Вопросов несколько:
Зачем нужен атрибут с подчёркиванием, если они одинаковые:
t.age = 12
print(t.age) # 12
print(t._Person__age) # 12
При этом vars() выводит только {'_Person__age': 12}
- Почему без подчёркиваний получаю ошибку?
Заранее спасибо
Ответы (1 шт):
Для данного кода, не касаясь искажения имен при наследовании: подчеркивания (два, одно или три) или любые другие символы нужны для того, чтобы переменная не называлась так же, как геттеры и сеттеры. Если они называются так же, как переменная, получается бесконечная рекурсия.
Когда вы в __init__() делаете присвоение self.age = 0, то не создается свойства age, а происходит вызов age(self, 0), где создается свойство __age и ему присваивается значение 0.
Назовите свойство вместо __age, например, rage - будет работать так же.
Просто согласно PEP8 договорились о том, чтобы применять подчеркивания.