it-swarm-pt.tech

Por que os métodos 'privados' do Python não são realmente privados?

O Python nos dá a capacidade de criar métodos e variáveis ​​'privados' dentro de uma classe, colocando dois underscores no nome, como: __myPrivateMethod(). Como, então, podemos explicar isso

>>> 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!!

Qual é o problema ?!

Vou explicar isso um pouco para aqueles que não entendem isso.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
... 
>>> obj = MyClass()

O que eu fiz lá é criar uma classe com um método público e um método privado e instanciá-lo.

Em seguida, chamo seu método público.

>>> obj.myPublicMethod()
public method

Em seguida, 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 bem aqui; somos incapazes de chamá-lo. Na verdade, é "privado". Bem, na verdade não é. Executar dir () no objeto revela um novo método mágico que o python cria magicamente para todos os seus métodos 'privados'.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

O nome desse novo método é sempre um sublinhado, seguido pelo nome da classe, seguido pelo nome do método.

>>> obj._MyClass__myPrivateMethod()
this is private!!

Tanto para o encapsulamento, né?

De qualquer forma, eu sempre ouvi que o Python não suporta o encapsulamento, então por que tentar? O que da?

557
willurd

O nome scrambling é usado para garantir que as subclasses não substituam acidentalmente os métodos e atributos privados de suas superclasses. Não foi projetado 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, ele se divide se duas classes diferentes tiverem o mesmo nome.

524
Alya

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 ###
206
arun

Quando vim pela primeira vez de Java para Python I odiava isso. Isso me assustou até a morte.

Hoje pode ser apenas uma coisa eu amo mais sobre o Python.

Eu adoro estar em uma plataforma, onde as pessoas confiam umas nas outras e não sentem que precisam construir muros impenetráveis ​​em torno de seu código. Em idiomas altamente encapsulados, se uma API tiver um bug e você descobrir o que está errado, talvez ainda não consiga contorná-la, porque o método necessário é privado. Em Python a atitude é: "sure". Se você acha que entende a situação, talvez até tenha lido, então tudo o que podemos dizer é "boa sorte!".

Lembre-se de que o encapsulamento não está nem fracamente relacionado à "segurança" nem ao manter as crianças fora do gramado. É apenas outro padrão que deve ser usado para tornar uma base de código mais fácil de entender.

141
Thomas Ahle

De http://www.faqs.org/docs/diveintopython/fileinfo_private.html

Estritamente falando, os métodos privados são Acessíveis fora de sua classe, apenas Não facilmente acessíveis. Nada em Python é verdadeiramente privado; internamente, os nomes de métodos privados e atributos são mutilados e não manipulados na hora para fazê-los parecer inacessíveis por seus nomes. Você Pode acessar o método __parse da classe MP3FileInfo com o nome _MP3FileInfo__parse. Reconheça que isso é interessante, então prometa a Nunca, nunca faça isso em código real. Métodos privados são privados por uma razão , Mas como muitas outras coisas em Python, sua privacidade é Em última análise, uma questão de convenção, não Força.

134
xsl

A frase comumente usada é "estamos todos consentindo adultos aqui". Ao prefixar um único sublinhado (não expor) ou sublinhado duplo (ocultar), você está dizendo ao usuário da sua classe que pretende que o membro seja 'privado' de alguma forma. No entanto, você está confiando que todos os outros se comportem de maneira responsável e respeitem isso, a menos que tenham uma razão convincente para não (por exemplo, depuradores, conclusão de código).

Se você realmente precisa ter algo privado, pode implementá-lo em uma extensão (por exemplo, em C para CPython). Na maioria dos casos, no entanto, você simplesmente aprende a maneira pitônica de fazer as coisas.

86
Tony Meyer

Não é como se você absolutamente não pudesse contornar a privacidade dos membros em qualquer linguagem (aritmética de ponteiros em C++, Reflections in .NET/Java).

O ponto é que você recebe um erro se tentar chamar o método privado por acidente. Mas se você quer se atirar no pé, vá em frente e faça isso.

Edit: Você não tenta proteger suas coisas por encapsulamento OO, não é?

32
Maximilian

Um comportamento semelhante existe quando os nomes de atributos do módulo começam com um único sublinhado (por exemplo, _foo).

Os atributos do módulo nomeados como tal não serão copiados para um módulo de importação ao usar o método from*, por exemplo:

from bar import *

No entanto, isso é uma convenção e não uma restrição de idioma. Estes não são atributos privados; eles podem ser referenciados e manipulados por qualquer importador. Alguns argumentam que, por causa disso, o Python não pode implementar o encapsulamento verdadeiro.

12
Ross

É apenas uma daquelas escolhas de design de linguagem. Em algum nível eles são justificados. Eles fazem com que você precise ir muito longe do seu caminho para tentar chamar o método, e se você realmente precisa tanto assim, você deve ter uma boa razão!

Depuração ganchos e testes vêm à mente como possíveis aplicações, usadas de forma responsável, é claro.

12
ctcherry

A convenção de nomenclatura class.__stuff permite que o programador saiba que ele não deve acessar __stuff de fora. O nome mangling torna improvável que alguém faça isso por acidente.

É verdade que você ainda pode contornar isso, é ainda mais fácil do que em outras linguagens (o que a BTW também permite que você faça isso), mas nenhum programador de Python faria isso se ele se preocupa com o encapsulamento.

11
Nickolay

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 as regras de manipulação são projetadas principalmente para evitar acidentes; ainda é possível acessar ou modificar uma variável considerada privada. Isso pode até ser útil em circunstâncias especiais, como no depurador.

Mesmo que a pergunta seja antiga, espero que meu trecho possa ser útil.

3
Alberto

A preocupação mais importante sobre métodos e atributos privados é dizer aos desenvolvedores para não chamá-los fora da classe e isso é encapsulamento. pode-se entender mal a segurança do encapsulamento. quando alguém deliberadamente usa sintaxe como essa (abaixo) que você mencionou, você não quer encapsulamento.

obj._MyClass__myPrivateMethod()

Eu migrei do C # e no começo foi estranho para mim também, mas depois de um tempo cheguei à ideia de que apenas a maneira como os desenvolvedores de código Python pensam sobre OOP é diferente. 

2
Afshin Amiri

Por que os métodos 'privados' do Python não são realmente privados?

Pelo que entendi, eles can't são privados. Como a privacidade poderia ser aplicada?

A resposta óbvia é "membros privados só podem ser acessados ​​através de self", mas isso não funcionaria - self não é especial em Python, não é nada mais do que um nome comumente usado para o primeiro parâmetro de uma função.

0
user200783