Для чего подчеркивания в @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

Вопросов несколько:

  1. Зачем нужен атрибут с подчёркиванием, если они одинаковые:

    t.age = 12
    print(t.age) # 12
    print(t._Person__age) # 12

При этом vars() выводит только {'_Person__age': 12}

  1. Почему без подчёркиваний получаю ошибку?

Заранее спасибо


Ответы (1 шт):

Автор решения: Алексей Р

Для данного кода, не касаясь искажения имен при наследовании: подчеркивания (два, одно или три) или любые другие символы нужны для того, чтобы переменная не называлась так же, как геттеры и сеттеры. Если они называются так же, как переменная, получается бесконечная рекурсия. Когда вы в __init__() делаете присвоение self.age = 0, то не создается свойства age, а происходит вызов age(self, 0), где создается свойство __age и ему присваивается значение 0.

Назовите свойство вместо __age, например, rage - будет работать так же. Просто согласно PEP8 договорились о том, чтобы применять подчеркивания.

Здесь подробные объяснения

→ Ссылка