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


238

Відповідно до 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, чи я щось неправильно зрозумів? І хто інший такий - небудь спосіб зробити визначити функцію модуля , як приватні?


Справа не в тому, що diveintopython невірний, але в їх прикладі: >>> import fileinfo >>> m = fileinfo.MP3FileInfo() >>> m.__parse("/music/_singles/kairo.mp3") 1 Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'MP3FileInfo' instance has no attribute '__parse' fileinfo.MP3FileInfo () - це примірник класу. Що дає цей виняток, коли ви використовуєте подвійне підкреслення. Тоді як у вашому випадку ви не створили клас, ви просто створили модуль. Дивіться також: stackoverflow.com/questions/70528/…
Хомеро Есмеральдо,

Відповіді:


323

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

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


82
Ваша примітка на C ++ неправильна. Використовуючи #define private public, ви змінюєте код, який надсилається компілятору, і саме там відбувається зміна імені.
rhinoinpose

14
Також маніпулювання C ++ є неясним, але навряд чи секретним. Ви також можете «самоаналізувати» двійковий файл, створений C ++. ОТ, вибачте.
Проф. Фолкен

47
Як оновлення до @rhinoinrepose, це не просто некоректно, це невизначена поведінка відповідно до стандарту, щоб перевизначити ключове слово за допомогою макроса препроцесора.
Cory Kramer

3
@AlexMartelli Не static void foo()настільки приватний, як це стає. Він принаймні прихований до лінкера, і функція може бути видалена повністю за допомогою вбудовування.
користувач877329

3
У реальному житті людей притягують до кримінальної відповідальності, якщо вони порушують закони
Lay González

288

Між приватними класами та приватними модулями може виникнути плутанина .

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

А клас приватні починається з двома символами підкреслення (ака Dunder тобто d-ouble під Score)
Такий змінний мають свою назву «викривлене» включити ім'я класу і т.д.
Це все ще може бути доступні за межі класу логіки, через спотворене ім'я.
Незважаючи на те, що назва манґлінгу може слугувати легким засобом запобігання проти несанкціонованого доступу, її головне призначення - запобігти можливим зіткненням імен з членами класів предків. Дивіться смішне, але точне посилання Алекса Мартеллі на згоду на дорослих, коли він описує конвенцію, використану стосовно цих змінних.

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

Ну, TIL. Будь-яка причина, чому вони не застосовують рівень модуля __private_function? Я натрапив на це і через це потрапив помилки.
Санта

Дякую за добрі слова @Terrabits, але я з радістю став другим за Алексом (значно позаду!) У всьому "Python". Крім того, його відповіді, як правило, більш лаконічні та жартівливі, зберігаючи високий рівень авторитетності, надаючи Алексу великий внесок у мову та громаду.
mjv

1
@mjv Це було корисне пояснення! Дякую! Я деякий час був дуже спантеличений такою поведінкою. Я б хотів, щоб вибір був у тому, щоб викинути якусь помилку, окрім AttributeError, якщо ви намагалися безпосередньо отримати доступ до класу приватного; можливо, "PrivateAccessError" чи щось було б більш явним / корисним. (Оскільки помилка, що у неї немає атрибута, насправді не відповідає дійсності).
HFBrowning

82

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

Якщо ви визначите приватні імена в модулі, ці імена будуть імпортовані в будь-який скрипт, який використовує синтаксис, "імпорт_ ім'я_кодрата" Таким чином, якщо припустити, що ви правильно визначили у своєму прикладі модуль приватний, _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
...

1
куди ви вказуєте, які функції / бібліотеки імпортуються? в init .py?
FistOfFury

Немає ризику зіткнень з іменами, коли _namesвони викликаються import a- вони є доступними, як a._namesпри використанні цього стилю.
Йосія Йодер

@FistOfFury Так, ви вказуєте функції, імпортовані у __init__.pyфайл. Дивіться тут деяку допомогу в цьому.
Майк Вільямсон

29

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

2
Я думаю, що ОП має на меті написати функції, недоступні за межами, наприклад, комерційного пакету. У зв'язку з цим ця відповідь не є повною. Функція __bar () все ще доступна ззовні через f._foo__bar (). Тому подвійні підкреслення не роблять це приватним.
SevakPrime

24

Ви можете додати внутрішню функцію:

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

Щось таке, якщо вам дійсно потрібен такий рівень конфіденційності.


9
Чому це не найкраща відповідь?
сафай


1

вбудований у закриття або функції - це один із способів. Це звичайне явище в JS, хоча це не потрібно для не-браузерних платформ або працівників браузера.

У Python це здається трохи дивним, але якщо щось дійсно потрібно приховати, то це може бути спосіб. Більш суттєвим є використання API python та збереження речей, які потрібно приховати на C (чи іншій мові), мабуть, найкращий спосіб. Якщо цього не вдалося ввести код всередині функції, викликати його і повернути елементи, які потрібно експортувати.


-11

У Python є три режими через., Приватний, загальнодоступний і захищений. При імпортуванні модуля доступний лише загальнодоступний режим. Тому приватні та захищені модулі не можна викликати поза модулем, тобто, коли він імпортується.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.