В том-то и дело, что внутренние поля не входят в интерфейс, поэтому ты можешь их менять, как хочешь и когда угодно. А когда они у тебя входят в интерфейс, то ты их не можешь менять никогда.
А эта идея, что якобы ты можешь его сделать свойством в любой момент, когда нужно будет внутри всё переделать, тоже выглядит не ахти. Что у тебя получится, что половина будет в виде внутренних полей, а половина в виде свойств?
Вот у тебя был код
>>> class A:
... def __init__(self):
... self.a = 1
... self.b = 2
...
>>> def f():
... a = A()
... return a.a, a.b
...
>>> f()
(1, 2)
>>>
Вот ты заменил имя переменной в классе
>>> class A:
... def __init__(self):
... self.some_a = 1
... self.b = 2
...
>>> def f():
... a = A()
... return a.a, a.b
...
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f
AttributeError: 'A' object has no attribute 'a'
>>>
Вот ты исправил ошибку, чтобы функция увидела старое поле
>>> class A:
... def __init__(self):
... self.some_a = 1
... self.b = 2
...
... @property
... def a(self):
... return self.some_a
...
>>> def f():
... a = A()
... return a.a, a.b
...
>>> f()
(1, 2)
>>>
И что мы видим? Переменная
a - в виде свойства, а переменная
b - в виде поля. И тут возникает вопрос: а что переменная
b может быть изменена без лишних телодвижений или она используется где-то и надо будет делать из неё свойство?
По идее, ты должен был в функции f() изменить переменную
a.a на переменную
a.some_a, чтобы красоту класса сохранить. Но только функций таких может быть сто.
Ещё есть запись свойств, но это “уже совсем другая история, страна…”. (Просто не стал усложнять тут повествование.)