Estou vindo do mundo Java e lendo Python 3 Patterns, Recipes and Idioms, de Bruce Eckels .
Ao ler sobre classes, continua dizendo que no Python não há necessidade de declarar variáveis de instância. Você apenas os usa no construtor, e boom, eles estão lá.
Então, por exemplo:
class Simple:
def __init__(self, s):
print("inside the simple constructor")
self.s = s
def show(self):
print(self.s)
def showMsg(self, msg):
print(msg + ':', self.show())
Se isso for verdade, qualquer objeto da classe Simple
pode apenas alterar o valor da variável s
fora da classe.
Por exemplo:
if __name__ == "__main__":
x = Simple("constructor argument")
x.s = "test15" # this changes the value
x.show()
x.showMsg("A message")
Em Java, aprendemos sobre variáveis públicas / privadas / protegidas. Essas palavras-chave fazem sentido porque às vezes você deseja variáveis em uma classe às quais ninguém fora da classe tem acesso.
Por que isso não é necessário no Python?
Respostas:
É cultural. No Python, você não grava na instância ou nas variáveis de outras classes. Em Java, nada impede que você faça o mesmo se realmente quiser - afinal, você sempre pode editar a fonte da própria classe para obter o mesmo efeito. O Python descarta essa pretensão de segurança e incentiva os programadores a serem responsáveis. Na prática, isso funciona muito bem.
Se você deseja emular variáveis privadas por algum motivo, sempre pode usar o
__
prefixo do PEP 8 . O Python manipula os nomes das variáveis como__foo
para que elas não fiquem facilmente visíveis para o código fora da classe que as contém (embora você possa contornar isso se você estiver determinado o suficiente, assim como você pode contornar as proteções do Java se você trabalhar com isso )Pela mesma convenção, o
_
prefixo significa ficar longe, mesmo que você não seja tecnicamente impedido de fazê-lo . Você não brinca com as variáveis de outra classe que se parecem__foo
ou_bar
.fonte
Variáveis privadas em python são mais ou menos um hack: o intérprete renomeia intencionalmente a variável.
Agora, se você tentar acessar
__var
fora da definição de classe, ela falhará:Mas você pode facilmente se safar com isso:
Você provavelmente sabe que os métodos no OOP são invocados assim:
x.printVar() => A.printVar(x)
seA.printVar()
puder acessar algum campo emx
, esse campo também poderá ser acessado foraA.printVar()
... afinal, as funções são criadas para reutilização, não há poder especial dado às instruções internas.O jogo é diferente quando há um compilador envolvido ( privacidade é um conceito no nível do compilador ). Ele conhece a definição de classe com modificadores de controle de acesso, para que possa errar se as regras não estiverem sendo seguidas no momento da compilação
fonte
Como mencionado corretamente por muitos dos comentários acima, não vamos esquecer o objetivo principal dos Modificadores de Acesso: Ajudar os usuários de código a entender o que deve mudar e o que não deve. Quando você vê um campo particular, não brinca com ele. Portanto, é principalmente o açúcar sintático que é facilmente alcançado no Python pelos _ e __.
fonte
Há uma variação de variáveis privadas na convenção de sublinhado.
Existem algumas diferenças sutis, mas por uma questão de pureza ideológica de padrão de programação, é bom o suficiente.
Existem exemplos de decoradores privados que implementam mais de perto o conceito, mas o YMMV. Indiscutivelmente, também se poderia escrever uma definição de classe que use meta
fonte
__x
como uma variável dentro da classeA
é realmente reescrita pelo compilador_A__x
, ainda não é totalmente privada e ainda pode ser acessada._A__x
vir uma variável chamada , não vou tocá-la. Pode ser contagioso. Eu vou fugir disso."Em java, aprendemos sobre variáveis públicas / privadas / protegidas"
"Por que isso não é necessário em python?"
Pelo mesmo motivo, não é necessário em Java.
Você é livre para usar - ou não usar
private
eprotected
.Como programador de Python e Java, descobri isso
private
eprotected
são conceitos de design muito, muito importantes. Mas, como uma questão prática, em dezenas de milhares de linhas de Java e Python, eu nunca realmente usadoprivate
ouprotected
.Por que não?
Aqui está minha pergunta "protegida de quem?"
Outros programadores da minha equipe? Eles têm a fonte. O que significa protegido quando eles podem mudar isso?
Outros programadores em outras equipes? Eles trabalham para a mesma empresa. Eles podem - com um telefonema - obter a fonte.
Clientes? É uma programação de trabalho contratado (geralmente). Os clientes (geralmente) possuem o código.
Então, de quem - exatamente - eu estou protegendo?
fonte
Como mencionado anteriormente, você pode indicar que uma variável ou método é privado, prefixando-o com um sublinhado. Se você não acha que isso é suficiente, sempre pode usar o
property
decorador. Aqui está um exemplo:Dessa forma, alguém ou algo que faz referência
bar
está realmente fazendo referência ao valor de retorno dabar
função em vez da própria variável e, portanto, pode ser acessada, mas não alterada. No entanto, se alguém realmente quisesse, poderia simplesmente usar_bar
e atribuir um novo valor a ele. Não existe uma maneira segura de impedir que alguém acesse variáveis e métodos que você deseja ocultar, como já foi dito repetidamente. No entanto, usarproperty
é a mensagem mais clara que você pode enviar informando que uma variável não deve ser editada.property
também pode ser usado para caminhos de acesso getter / setter / deleter mais complexos, conforme explicado aqui: https://docs.python.org/3/library/functions.html#propertyfonte
O Python possui suporte limitado para identificadores particulares, por meio de um recurso que precede automaticamente o nome da classe a qualquer identificador começando com dois sublinhados. Isso é transparente para o programador, na maioria das vezes, mas o efeito líquido é que quaisquer variáveis nomeadas dessa maneira podem ser usadas como variáveis privadas.
Veja aqui para mais informações.
Em geral, a implementação de orientação a objetos do Python é um pouco primitiva em comparação com outras linguagens. Mas eu gosto disso, na verdade. É uma implementação muito conceitualmente simples e se encaixa bem no estilo dinâmico da linguagem.
fonte
O único momento em que uso variáveis privadas é quando preciso fazer outras coisas ao escrever ou ler a partir da variável e, como tal, preciso forçar o uso de um setter e / ou getter.
Novamente, isso vai para a cultura, como já foi dito. Eu tenho trabalhado em projetos em que a leitura e a escrita de outras variáveis de classe eram gratuitas para todos. Quando uma implementação ficou obsoleta, demorou muito mais tempo para identificar todos os caminhos de código que usavam essa função. Quando o uso de setters e getters foi forçado, uma instrução de depuração poderia ser facilmente escrita para identificar que o método descontinuado havia sido chamado e o caminho do código que o chama.
Quando você está em um projeto em que qualquer pessoa pode escrever uma extensão, notificar os usuários sobre métodos descontinuados que devem desaparecer em algumas versões é vital para manter a quebra do módulo no mínimo durante as atualizações.
Então minha resposta é; se você e seus colegas mantêm um conjunto de códigos simples, nem sempre é necessário proteger as variáveis de classe. Se você estiver escrevendo um sistema extensível, torna-se imperativo quando são feitas alterações no núcleo que precisam ser capturadas por todas as extensões usando o código.
fonte
Desculpe pessoal por "ressuscitar" o tópico, mas espero que isso ajude alguém:
No Python3, se você quiser apenas "encapsular" os atributos da classe, como em Java, você pode fazer o mesmo:
Para instanciar isso, faça:
Observe que:
print(ss.__s)
lançará um erro.Na prática, o Python3 ofuscará o nome do atributo global. Transformando isso como um atributo "privado", como em Java. O nome do atributo ainda é global, mas de maneira inacessível, como um atributo privado em outros idiomas.
Mas não tenha medo disso. Não importa. Também faz o trabalho. ;)
fonte
conceitos privados e protegidos são muito importantes. Mas python - apenas uma ferramenta para prototipagem e desenvolvimento rápido com recursos restritos disponíveis para desenvolvimento, é por isso que alguns dos níveis de proteção não são tão rigorosos seguidos no python. Você pode usar "__" no membro da classe, ele funciona corretamente, mas não parece bom o suficiente - cada acesso a esse campo contém esses caracteres.
Além disso, você pode notar que o conceito OOP do python não é perfeito, smaltalk ou ruby muito mais próximo do conceito OOP puro. Até C # ou Java estão mais próximos.
Python é uma ferramenta muito boa. Mas é uma linguagem OOP simplificada. Sintaticamente e conceitualmente simplificado. O principal objetivo da existência do python é trazer aos desenvolvedores a possibilidade de escrever código fácil de ler com alto nível de abstração de uma maneira muito rápida.
fonte
Python não possui nenhuma variável privada como C ++ ou Java. Você também pode acessar qualquer variável de membro a qualquer momento, se desejar. No entanto, você não precisa de variáveis privadas no Python, porque no Python não é ruim expor as variáveis de membro de suas classes. Se você precisar encapsular uma variável de membro, poderá fazer isso usando "@property" posteriormente, sem quebrar o código do cliente existente.
Em python, o sublinhado único "_" é usado para indicar que um método ou variável não é considerado parte da API pública de uma classe e que essa parte da API pode mudar entre versões diferentes. Você pode usar esses métodos / variáveis, mas seu código pode ser quebrado se você usar uma versão mais recente dessa classe.
O sublinhado duplo "__" não significa uma "variável privada". Você o utiliza para definir variáveis que são "classe local" e que não podem ser facilmente substituídas por subclasses. Ele gerencia o nome das variáveis.
Por exemplo:
self .__ foobar nome é automaticamente mutilado para self._A__foobar na classe A. Na classe B é mutilado para self._B__foobar. Portanto, cada subclasse pode definir sua própria variável __foobar sem substituir as variáveis-mãe. Mas nada impede que você acesse variáveis que começam com sublinhados duplos. No entanto, a manipulação de nomes impede que você chame essas variáveis / métodos por acaso.
Eu recomendo assistir Raymond Hettingers falar sobre "Pythons class development toolkit" do Pycon 2013 (deve estar disponível no Youtube), o que dá um bom exemplo de por que e como você deve usar as variáveis @property e "__" - instance.
fonte
@property
parte do Python padrão ou é específico para um IDE?property
função embutida, que está disponível desde o python 2.2.Na verdade, você pode simular um
C#
getter e um setter usando este truque simples:Em seguida, use-o semelhante como em
C#
:É apenas declarar uma variável local estática em uma função que desempenhará uma função get / set, pois essa é a única maneira de compartilhar uma variável por meio de métodos get e set, sem torná-la global para uma classe ou arquivo.
fonte