Oi Franco, como você está? Espero que esteja bem ^-^
Antes de irmos à pergunta, vamos recapitular alguns pontos:
Em python nada é verdadeiramente privado, sempre haverá uma forma de acessarmos o atributo fora da classe, tanto no uso de um quanto no de dois undescores. Quando utilizamos o duplo undescore, o que ocorre é que o programa modifica o nome do atributo para que ele seja de difícil acesso do lado externo da classe, mas, mesmo assim é possível acessá-lo.
Suponha o atributo __nome
de uma classe Animal
. Para acessarmos esse atributo do lado externo da classe, podemos fazer: _Animal__nome
, isso é chamado de desconfiguração de nomes (name mangling), onde a sintaxe é: um underscore seguido do nome da classe e em seguida, o duplo underscore seguido do nome do atributo, porém, isso tem a ver com proteção e não com segurança. Isso foi feito para evitar acessos acidentais e não contra ações maliciosas intencionais, pois, qualquer pessoa que saiba sobre como os atributos de duplo undercore são desconfigurados, poderá lê-los fora da classe, veja um exemplo:
class Animal:
def __init__(self, nome):
self.__nome = nome
cachorro = Animal("Bob")
cachorro._Animal__nome
# Resultado
Bob
E não apenas lê-lo fora da classe, mas também, modificá-lo:
cachorro = Animal("Bob")
print(cachorro._Animal__nome)
cachorro._Animal__nome = "Pity"
print(cachorro._Animal__nome)
# Resultado
Bob
Pity
Na comunidade Python, é convenção o uso de um único undescore como prefixo para "proteger" o atributo e é algo bem respeitado, pois, quando avistamos uma variável precedida pelo undescore, sabemos que aquele atributo funciona como privado, apesar de não ser verdadeiramente assim, tal como na linguagem Java. Esta convenção é definida na própria documentação da linguagem. Geralmente utiliza-se o duplo undescore quando queremos nos aproximar aos conceitos de atributo privado presente em outras linguagens. A escolha de um ou de outro varia de programador para programador, mas, deve-se manter uma consistência, se utilizar um undescore, que o utilize sempre, se utilize o duplo, que o utilize sempre, para não ficar algo desorganizado no código.
Dito isso, então como acessar atributos privados da classe dentro de outros métodos dessa mesma classe?
Quanto ao acesso dele, tanto dentro quanto fora da classe, a maneira "pythônica" de se fazer é através de propertys, até mesmo na inicialização da classe, veja um exemplo:
class Animal:
def __init__(self, nome):
self.nome = nome
@property
def nome(self):
return self.__nome
@nome.setter
def nome(self, nome):
print("Chamando o setter")
self.__nome = nome
cachorro = Animal("Bob")
# Resultado
Chamando o setter
No exemplo acima, estamos utilizando a property de setter implicitamente no nosso método inicializador da classe e dentro do setter, criamos um atributo "privado" com duplo undescore. Essa é uma boa prática, trabalhar com propertys dentro da classe, uma vez que as mesmas já estão a disposição e por vezes, o property de setter pode até mesmo contar com validações. Como mostro abaixo:
class Quadrado:
def __init__(self, lado):
self.lado = lado
@property
def lado(self):
return self.__lado
@lado.setter
def lado(self, lado):
print("Chamando o setter")
if lado > 3:
self.__lado = lado
else:
raise ValueError("O valor do lado tem que ser maior que 3")
Espero ter esclarecido sua dúvida e qualquer coisa, vamos conversando :D
Grande abraço!