Por que Python 'privado' métodos, na verdade, não privada?
-
09-06-2019 - |
Pergunta
Python nos dá a capacidade de criar 'privado' métodos e variáveis dentro de uma classe, inserindo duplo sublinhado para o nome, como este: __myPrivateMethod()
.Como, então, explicar essa
>>> class MyClass:
... def myPublicMethod(self):
... print 'public method'
... def __myPrivateMethod(self):
... print 'this is private!!'
...
>>> obj = MyClass()
>>> obj.myPublicMethod()
public method
>>> obj.__myPrivateMethod()
Traceback (most recent call last):
File "", line 1, in
AttributeError: MyClass instance has no attribute '__myPrivateMethod'
>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
>>> obj._MyClass__myPrivateMethod()
this is private!!
O que é o negócio?!
Vou explicar um pouco para aqueles que não entendia muito isso.
>>> class MyClass:
... def myPublicMethod(self):
... print 'public method'
... def __myPrivateMethod(self):
... print 'this is private!!'
...
>>> obj = MyClass()
O que eu fiz foi criar uma classe com um método público e privado, método e instanciá-lo.
Em seguida, chamar o método público.
>>> obj.myPublicMethod()
public method
Seguinte, eu tento chamar seu método particular.
>>> obj.__myPrivateMethod()
Traceback (most recent call last):
File "", line 1, in
AttributeError: MyClass instance has no attribute '__myPrivateMethod'
Tudo parece bom aqui;podemos chamá-lo.É, na verdade, de "privado".Bem, de facto não o é.Execução dir() sobre o objeto revela um novo e mágico, o método que o python cria mágica para todos os seus 'privado' métodos.
>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
Este novo método é sempre um carácter de sublinhado, seguido do nome da classe, seguido do nome do método.
>>> obj._MyClass__myPrivateMethod()
this is private!!
Tanto para o encapsulamento, hein?
Em qualquer caso, eu sempre ouvi dizer que o Python não oferece suporte a encapsulamento, então, por que mesmo tentar?O que dá?
Solução
O nome de embaralhamento é usado para garantir que subclasses não acidentalmente substituir o privado, métodos e atributos de suas superclasses.Ele não foi concebido para impedir o acesso deliberado de fora.
Por exemplo:
>>> class Foo(object):
... def __init__(self):
... self.__baz = 42
... def foo(self):
... print self.__baz
...
>>> class Bar(Foo):
... def __init__(self):
... super(Bar, self).__init__()
... self.__baz = 21
... def bar(self):
... print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}
É claro que, se decompõe se a duas classes diferentes têm o mesmo nome.
Outras dicas
Exemplo de função privada
import re
import inspect
class MyClass :
def __init__(self) :
pass
def private_function ( self ) :
try :
function_call = inspect.stack()[1][4][0].strip()
# See if the function_call has "self." in the begining
matched = re.match( '^self\.', function_call )
if not matched :
print 'This is Private Function, Go Away'
return
except :
print 'This is Private Function, Go Away'
return
# This is the real Function, only accessible inside class #
print 'Hey, Welcome in to function'
def public_function ( self ) :
# i can call private function from inside the class
self.private_function()
### End ###
Quando vim pela primeira vez a partir de Java, Python eu odiava isso.Ele me assustou até a morte.
Hoje, ele só poderia ser uma coisa Eu te amo mais sobre o Python.
Eu amo estar em uma plataforma, onde as pessoas confiam umas nas outras e não se sentir como eles precisam para construir impenetrável paredes em torno de seus códigos.No fortemente encapsulado línguas, se uma API tem um erro, e você tem de descobrir o que der errado, você pode ainda não ser possível contornar isso porque o método necessário é privado.Em Python, a atitude é:"com certeza".Se você acha que você compreender a situação, talvez você tenha até mesmo de lê-lo, então tudo o que podemos dizer é "boa sorte!".
Lembre-se, o encapsulamento não é mesmo fracamente relacionadas com "segurança", ou de manter as crianças fora do gramado.É apenas outro padrão que deve ser usado para fazer uma base de código mais fácil de entender.
A partir de http://www.faqs.org/docs/diveintopython/fileinfo_private.html
Estritamente falando, métodos privados são acessíveis fora da classe, apenas não é facilmente acessível.Nada Python é verdadeiramente privada;internamente, os nomes de métodos particulares e atributos são deturpados e unmangled na mosca, para fazê-los parecer inacessível por seus nomes.Você pode aceder a __método de análise do MP3FileInfo classe com o nome _MP3FileInfo__analisar.Reconhecem que isso é interessante, então prometo nunca, nunca fazê-lo no código real.Métodos Private são privados de uma a razão, mas como muitas outras coisas no Python, seus privateness é em última análise, uma questão de convenção, não força.
A frase comumente usada é "somos todos adultos aqui".Por prefixação um único carácter de sublinhado (não exponha) ou sublinhado duplo (ocultar), você está dizendo para o usuário de sua classe que pretende o membro a ser 'privado' de alguma forma.No entanto, você estiver confiante com que todos os outros se comportam de forma responsável e o respeito que, a menos que tenha uma razão muito forte para não (e.g.depuradores, conclusão de código).
Se você realmente deve ter algo que é particular, então você pode implementá-lo em uma extensão (por exemplo,em C para o CPython).Na maioria dos casos, no entanto, você simplesmente aprender a Pythonic maneira de fazer as coisas.
Não é como se você absolutamente não pode ficar em torno de privateness de membros em qualquer língua (aritmética de ponteiro em C++, Reflexões .NET/Java).
O ponto é que você receber um erro se você tentar chamar o método privado por acidente.Mas se você quiser atirar no próprio pé, vá em frente e faça isso.
Editar:Você não tentar garantir que o seu material por OO-encapsulação, não é?
O class.__stuff
convenção de nomenclatura permite que o programador sabe que ele não foi criado para acesso __stuff
a partir de fora.O nome desconfiguração torna improvável que alguém vai fazer isso por acidente.
É verdade, você ainda pode contornar isto, é até mais fácil do que em outras línguas (que BTW também permite que você faça isso), mas nenhum programador Python iria fazer isso se ele se preocupa com o encapsulamento.
Comportamento semelhante existe quando o módulo de atributo de nomes começam com um único carácter de sublinhado (por exemplo,_foo).
Módulo de atributos chamado como tal não irá ser copiado para um módulo de importação quando utilizar o from*
o método, por exemplo:
from bar import *
No entanto, esta é uma convenção e não uma linguagem de restrição.Esses não são atributos privados;eles podem ser referenciados e manipulados por qualquer importador.Alguns argumentam que, devido a isso, o Python não pode implementar verdadeiro encapsulamento.
É apenas um daqueles idioma opções de design.Em algum nível, eles são justificados.Eles fazem isso para que você precisa ir muito longe, fora do seu caminho para tentar chamar o método, e se você realmente precisa que o mal, você deve ter uma boa razão!
A depuração de ganchos e testes vêm à mente como possíveis aplicações, o uso responsável de curso.
Com o Python 3.4 este é o comportamento:
>>> class Foo:
def __init__(self):
pass
def __privateMethod(self):
return 3
def invoke(self):
return self.__privateMethod()
>>> help(Foo)
Help on class Foo in module __main__:
class Foo(builtins.object)
| Methods defined here:
|
| __init__(self)
|
| invoke(self)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
>>> f = Foo()
>>> f.invoke()
3
>>> f.__privateMethod()
Traceback (most recent call last):
File "<pyshell#47>", line 1, in <module>
f.__privateMethod()
AttributeError: 'Foo' object has no attribute '__privateMethod'
https://docs.python.org/3/tutorial/classes.html#tut-private
Observe que a desconfiguração regras são projetados principalmente para evitar acidentes; ainda é possível acessar ou modificar uma variável que é considerado privado. Isso pode até ser útil em circunstâncias especiais, como no depurador.
Mesmo se a questão é antiga, eu espero que o meu trecho poderia ser útil.
A preocupação mais importante sobre o privado, métodos e atributos, é dizer que os desenvolvedores não chamá-lo de fora da classe e este é o encapsulamento.pode-se entender mal de segurança de encapsulamento.quando um deliberadamente usa a sintaxe como que(abaixo) que você mencionou, você não quer que o encapsulamento.
obj._MyClass__myPrivateMethod()
Eu ter migrado a partir do C#, e no começo foi estranho para mim também, mas depois de um tempo me veio a idéia de que apenas a forma que o Python de código designers a pensar sobre OOP é diferente.
Por que Python 'privado' métodos, na verdade, não privada?
Como eu a entendo, eles não pode ser privado.Como poderia privacidade será aplicada?
A resposta óbvia é "membros privados só podem ser acessados através self
", mas que não iria funcionar - self
não é especial em Python, ele é nada mais do que uma comumente usada nome para o primeiro parâmetro de uma função.