Почему "частные" методы Python на самом деле не частная?


Python дает нам возможность создавать "частные" методы и переменные внутри класса, добавляя к имени двойные подчеркивания, например:__myPrivateMethod(). Как же тогда объяснить это

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

в чем дело?!

я объясню это немного для тех, кто не совсем понял это.

>>> 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 () на объекте раскрывается новый магический метод, который python создает волшебным образом для всех ваших "частных" методов.

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

имя этого нового метода всегда является подчеркиванием, за которым следует имя класса, а затем метод имя.

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

так много для инкапсуляции, а?

в любом случае, я всегда слышал, что Python не поддерживает инкапсуляцию, так зачем даже пытаться? Что это дает?

11 518

11 ответов:

скремблирование имен используется для обеспечения того, чтобы подклассы случайно не переопределяли частные методы и атрибуты своих суперклассов. Он не предназначен для предотвращения преднамеренного доступа извне.

например:

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

конечно, он ломается, если два разных класса имеют одинаковое имя.

пример собственной функции

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

от http://www.faqs.org/docs/diveintopython/fileinfo_private.html

строго говоря, частные методы доступный вне их класса, просто не так легко добраться. Ничего Python действительно частный; внутренне, имена частных методов и атрибуты искажены и не перепутаны на лету, чтобы они казались недоступные по их именам. Вы может получить доступ к методу __parse Класс MP3FileInfo по имени _MP3FileInfo__парсить. Признайте, что это интересно, тогда обещайте никогда, никогда не делайте этого в реальном коде. Частные методы являются частными для причина, но, как и многие другие вещи в Питон, их приватность-это в конечном счете, это вопрос конвенции, а не сила.

когда я впервые пришел с Java на Python I ненавидит этого. Это напугало меня до смерти.

сегодня это может быть одно Я люблю больше всего о Python.

Мне нравится быть на платформе, где люди доверяют друг другу и не чувствуют, что им нужно строить непроницаемые стены вокруг своего кода. В сильно инкапсулированных языках, если API имеет ошибку, и вы выяснили, что идет не так, вы все равно не сможете ее обойти, потому что необходимый метод является частным. В Python отношение такое:"конечно". Если вы думаете, что понимаете ситуацию, возможно, вы даже читали ее, тогда все, что мы можем сказать: "удачи!".

помните, инкапсуляция даже не слабо связана с" безопасностью " или удержанием детей от лужайки. Это просто еще один шаблон, который следует использовать для облегчения понимания базы кода.

обычно используется фраза "Мы все согласны взрослые здесь". Добавляя одно подчеркивание (не раскрывать) или двойное подчеркивание (скрыть), вы сообщаете пользователю своего класса, что вы намереваетесь, чтобы член был "частным" в некотором роде. Однако Вы доверяете всем остальным вести себя ответственно и уважать это, если у них нет веской причины не делать этого (например, отладчики, завершение кода).

Если вы действительно должны иметь что-то личное, то вы можете реализовать его в расширении (например, в C для CPython). В большинстве случаев, однако, вы просто изучаете Питонический способ делать вещи.

Это не похоже на то, что вы абсолютно не можете обойти приватность членов на любом языке (арифметика указателя в C++, отражения в .NET / Java).

дело в том, что вы получаете ошибку, если вы пытаетесь вызвать частный метод случайно. Но если вы хотите выстрелить себе в ногу, идти вперед и делать это.

Edit: вы не пытаетесь защитить свои вещи с помощью OO-инкапсуляции, не так ли?

подобное поведение существует, когда имена атрибутов модуля начинаются с одного подчеркивания (например, _foo).

атрибуты модуля с такими именами не будут скопированы в модуль импорта при использовании from* способ, например:

from bar import *

однако это соглашение, а не языковое ограничение. Это не частные атрибуты; на них может ссылаться и ими может манипулировать любой импортер. Некоторые утверждают, что из-за этого, Python не может реализовать истинный инкапсуляция.

Это просто один из вариантов дизайна языка. На каком-то уровне они оправданы. Они делают это так, что вам нужно идти довольно далеко от вашего пути, чтобы попытаться вызвать метод, и если вам действительно это нужно так сильно, у вас должна быть довольно веская причина!

отладочные крючки и тестирование приходят на ум как возможные приложения, используемые ответственно, конечно.

The class.__stuff соглашение об именах позволяет программисту знать, что он не предназначен для доступа __stuff извне. Название mangling делает маловероятным, что кто-то сделает это случайно.

правда, вы все еще можете обойти это, это даже проще, чем на других языках (которые кстати также позволяют вам это делать), но ни один программист Python не сделает этого, если он заботится об инкапсуляции.

С Python 3.4 это поведение:

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

обратите внимание, что правила калечения предназначены в основном для предотвращения несчастных случаев;он по-прежнему можно получить доступ или изменить переменную, которая является частной. это может быть даже полезно в особых обстоятельствах, например, в отладчике.

даже если вопрос старый, я надеюсь, что мой фрагмент могут быть полезными.

самая важная забота о частных методах и атрибутах-это сказать разработчикам не вызывать его вне класса, и это инкапсуляция. можно неправильно понять безопасность от инкапсуляции. когда вы намеренно используете такой синтаксис (ниже), вы не хотите инкапсуляции.

obj._MyClass__myPrivateMethod()

я перешел с C#, и сначала это было странно для меня тоже, но через некоторое время я пришел к мысли, что только так, как дизайнеры кода Python думают о ООП отличающийся.