Определение функций частного модуля в Python - PullRequest
203 голосов
/ 10 октября 2009

Согласно 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 неправильно, или я что-то неправильно понял? И есть ли способ do определить функцию модуля как приватную?

Ответы [ 8 ]

273 голосов
/ 10 октября 2009

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

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

255 голосов
/ 10 октября 2009

Может быть путаница между рядовыми и рядовыми .

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

A класс приватный начинается с два подчеркивания (он же dunder, т.е. d-ouble знак ниже)
Такая переменная имеет название "искаженный", чтобы включать имя класса и т. Д.
К нему все еще можно получить доступ за пределами логики класса через искаженное имя.
Хотя искажение имени может служить средством для предотвращения несанкционированного доступа, его основная цель - предотвратить возможные конфликты имен с членами классов классов-предков. См. Забавную, но точную ссылку Алекса Мартелли на согласных взрослых , поскольку он описывает соглашение, используемое в отношении этих переменных.

>>> 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
>>>
73 голосов
/ 29 ноября 2012

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

Если вы определите личные имена в модуле, эти имена будут импортированы в любой сценарий, использующий синтаксис '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
...
29 голосов
/ 10 октября 2009

Python допускает закрытые члены class с двойным префиксом подчеркивания. Эта техника не работает на уровне модулей, поэтому я думаю, что это ошибка в 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
7 голосов
/ 30 марта 2018

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

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

Что-то в этом роде, если вам действительно нужен такой уровень конфиденциальности.

1 голос
/ 14 сентября 2017

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

Учебник по Python » Классы » Частные переменные

0 голосов
/ 14 января 2018

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

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

0 голосов
/ 18 июня 2016

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

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