Oi Otavio! Como vai?
Cada self que definimos dentro do init, será um atributo dos objetos criados dentro dessa classe.
def __init__(self, x, y):
self.__x = x
self.__y = y
self.__area = x * y
Pode perceber que o atributo utilizado para o funcionamento do método obter_area chama-se "__area" e não "area".
def obter_area(self):
return self.__area
Quando fazemos:
r.area = 7
Não estamos mudando o atributo usado na função, estamos atribuindo valor a um atributo que ainda não existe. Pois o atributo criado previamente chama-se __area e não area. E é por isso que o resultado do exercício permanece 42.
Entretanto, depois que atribuímos valor a um atributo que ainda não existe, criamos ele manualmente para aquele objeto!
Como você pode conferir na imagem abaixo, no canto direito estão todos os atributos daquele objeto. Depois que atribuí um valor ao r, ele apareceu no canto direito como um atributo.
![](https://i.ibb.co/8rqynxm/python-area.png)
Depois de fazer isso, verá que quando escrever "r.", aparacerá a opção area, como na imagem abaixo:
![](https://i.ibb.co/N1Sk1mz/python-area-2.png)
Alem disso, é preciso levar em consideração que __area se trata de um atributo privado, para acessá-lo, embora não seja recomendado acessar diretamente um atributo privado, é necessário chamar a classe antes dele como no exemplo abaixo:
r._Retangulo__area
Por favor, me avise se fez sentido. Caso não, posso te explicar de outra maneira =)