Olá, Giovanni! Sua pergunta é muito boa e importante, afinal temos algumas peculiaridades no funcionamento do paradigma de Orientação a Objetos na linguagem Python.
Se você vem de uma linguagem completamente voltada à orientação a objetos, como é Java, por exemplo, provavelmente está acostumado a algumas regras e restrições diferentes do que as que o Python nos provide. Para começar, digo logo - não existem atributos privados no Python! Ou melhor, ao menos como normalmente conhecemos.
Deixa eu explicar: Por boas práticas, quando trabalhamos com orientação a objetos no Python, é comum indicarmos que um atributo de uma classe deve ser privado, isto é, não deve ser mexido por outras classes, com um underline (_
) na frente do nome da variável, dessa forma:
class Perfil(object):
def __init__(self):
self._curtidas = 0
def curtir(self):
self._curtidas += 1
def obter_curtidas(self):
return self._curtidas
Como você deve imaginar, isso não restringe acesso nenhum ao atributo, mas apenas indica ao desenvolvedor que não é recomendável modificar este atributo fora da classe:
>>> perfil = Perfil()
>>> perfil.curtir()
>>> perfil.obter_curtidas()
1
>>> perfil._curtidas = 5
>>> perfil.obter_curtidas()
5
Certo! Mas também temos o que foi visto no curso, que foi a tentativa de tornar o atributo privado com os dois underlines (__
) na frente do nome da variável. Como já testamos, realmente não é possível acessar essa variável do jeito que esperaríamos que funcionasse:
>>> perfil = Perfil()
>>> perfil.curtir()
>>> perfil.obter_curtidas()
1
>>> perfil.__curtidas = 5
>>> perfil.obter_curtidas()
1
Ok! Mas será que realmente não temos como acessar o atributo __curtidas
fora da classe? Olha isso:
>>> perfil = Perfil()
>>> perfil.curtir()
>>> perfil.obter_curtidas()
1
>>> perfil._Perfil__curtidas = 5
>>> perfil.obter_curtidas()
5
Conseguimos acessar o atributo __curtidas
por fora da classe! O que acontece é que o Python, quando colocamos __
na frente de um nome de um atributo de uma classe, apenas renomeia esse atributo automaticamente de __atributo
para _Classe__atributo
, como fez de __curtidas
para _Perfil__curtidas
.
Isso, de fato, quebra o encapsulamento que conhecemos em linguagens como Java. A questão é que, no Python, a filosofia Pythônica é mais importante que o encapsulamento padrão. Encapsulamento existe no Python (é importante entender isso!), mas a linguagem não vai te proibir, isto é, impedir de tomar suas próprias decisões. Uma frase muito comum no mundo Python é we are all consenting adults here, ou, em uma tradução ao pé da letra, somos todos adultos com consentimento aqui. Podemos (e, na verdade, devemos!) indicar quais são as preferências para uso e continuação de nosso código, ou seja, se queremos, por exemplo, que um atributo seja acessado por fora de sua classe, mas realmente precisamos proibir o desenvolvedor de tomar suas próprias decisões? A filosofia Pythônica diz que não!
Enfim, para que serve, então, o comportamento dos atributos que começam com dois underlines (__
)? De certa forma, como vimos, ele esconde o atributo, funcionando como encapsulamento. Além disso, é perfeito para o ponto que você indicou como problema: sobreposição de nomes de variáveis. Se precisarmos, ou melhor, querermos ter dois atributos com o "mesmo" nome, podemos usar esse comportamento ao nosso favor, como você mesmo demonstrou, já que o atributo __curtidas
declarado dentro da classe (que é renomeado para _Perfil__curtidas
é diferente do atributo __curtidas
declarado fora da classe (que fica com o nome __curtidas
). Como você mesmo indicou, temos que tomar cuidado com isso, para não criarmos um código confuso, mas, na verdade, isso não quebra o encapsulamento, afinal o atributo __curtidas
definido dentro da classe continua não sendo acessado por fora dela.
Deu pra entender mais ou menos o que eu quis dizer, Giovanni, hehe? Dá um feedback aqui, pra se algo tiver ficado confuso!
Outra coisa, se você se interessa mais pela filosofia e as ideias por trás do Python, recomendo duas leituras para você. Uma é o PEP 8, que é um guia de estilo para código Python e acaba tratando bastante da filosofia pythônica.
A outra leitura, também muito interessante, é, na verdade, um easter egg no Python. Não vou te falar o resultado, mas tente, no console Python, digitar o seguinte código:
>>> import this
e diga o que acha!
Abraços e bons estudos!