Определение функций частного модуля в python

Согласно http://www.faqs.org/docs/diveintopython/fileinfo_private.html:

Как и большинство языков, Python имеет концепция частных элементов:

  • Частный функции, которые не могут быть вызваны из вне их модуля

Однако, если я определяю два файла:

#a.py
__num=1

и

#b.py
import a
print a.__num

когда я запускаю b.py, он выводит 1 без каких-либо исключений. Является ли diveintopython неправильным, или я что-то неправильно понял? И есть ли способ сделать определить функцию модуля как конфиденциальную?

Ответ 1

В Python "конфиденциальность" зависит от уровня согласия "согласных взрослых" - вы не можете заставить его (больше, чем вы можете в реальной жизни;-). Единственное подчеркивание означает, что вы не предположили для доступа к нему "извне" - два ведущих подчеркивания (без подчеркивания подчеркивания) переносят сообщение еще более убедительно... но, в конце концов, это все еще зависит от социальной конвенции и консенсуса: интроспекция Python достаточно сильная, чтобы вы не могли наручники всех других программистов в мире уважать ваши пожелания.

((Btw, хотя он тесно связан с секретом, то же самое имеет место для С++: с большинством компиляторов простая строка #define private public до #include в вашем файле .h - все, что нужно, чтобы коварные кодеры хэш вашей "конфиденциальности"...! -))

Ответ 2

Может возникнуть путаница между class privates и модулем privates.

Закрытый модуль начинается с одного подчеркивания
Такой элемент не копируется при использовании формы from <module_name> import * команды import; он импортируется, если используется синтаксис import <moudule_name> (см. ответ Бен Вильгельма)
Просто удалите одно подчеркивание из a.__ num примера вопроса, и оно не будет отображаться в модулях, которые импортируют a.py с помощью синтаксиса from a import *.

Класс private начинается с двух подчеркиваний (aka dunder i.e. d-ouble under-score)
Такая переменная имеет свое имя "mangled", чтобы включить имя класса и т.д.
Его все равно можно получить за пределами логики класса, через искаженное имя.
Хотя название mangling может служить в качестве устройства для предотвращения несанкционированного доступа, его основная цель - предотвратить возможные столкновения имен с членами класса предков. См. Alex Martelli, смешную, но точную ссылку на соглашающихся взрослых, поскольку он описывает соглашение, используемое в отношении этих переменных.

>>> class Foo(object):
...    __bar = 99
...    def PrintBar(self):
...        print(self.__bar)
...
>>> myFoo = Foo()
>>> myFoo.__bar  #direct attempt no go
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__bar'
>>> myFoo.PrintBar()  # the class itself of course can access it
99
>>> dir(Foo)    # yet can see it
['PrintBar', '_Foo__bar', '__class__', '__delattr__', '__dict__', '__doc__', '__
format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__
', '__subclasshook__', '__weakref__']
>>> myFoo._Foo__bar  #and get to it by its mangled name !  (but I shouldn't!!!)
99
>>>

Ответ 3

Этот вопрос не получил полного ответа, поскольку конфиденциальность модуля не является чисто условной, и поскольку использование import может или не может распознавать конфиденциальность модуля, в зависимости от того, как он используется.

Если вы определяете личные имена в модуле, те имена будут импортированы в любой script, который использует синтаксис, 'import module_name'. Таким образом, предполагая, что вы правильно определили в своем примере модуль private, _num, в a.py, вот так..

#a.py
_num=1

.. вы могли бы получить к нему доступ в b.py с символом имени модуля:

#b.py
import a
...
foo = a._num # 1

Чтобы импортировать только не-приватных из a.py, вы должны использовать синтаксис от:

#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined

Для ясности, однако, лучше быть явным при импорте имен из модулей, а не импортировать их все с помощью "*":

#b.py
from a import name1 
from a import name2
...

Ответ 4

Python позволяет частным членам класса с двойным префиксом подчеркивания. Этот метод не работает на уровне модуля, поэтому я думаю, что это ошибка в Dive Into Python.

Вот пример функций частного класса:

class foo():
    def bar(self): pass
    def __bar(self): pass

f = foo()
f.bar()   # this call succeeds
f.__bar() # this call fails

Ответ 5

Вы можете добавить внутреннюю функцию:

def public(self, args):
   def private(self.root, data):
       if (self.root != None):
          pass #do something with data

Нечто подобное, если вам действительно нужен такой уровень конфиденциальности.

Ответ 6

Это древний вопрос, но в стандартной документации теперь рассматриваются как частные, так и частные символы (одно подчеркивание) и класс-частный (два символа подчеркивания):

Учебник Python " Classes "Частные переменные

Ответ 7

встроенный с замыканиями или функциями является одним из способов. Это часто встречается в JS, но не требуется для не браузерных платформ или работников браузеров.

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

Ответ 8

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