Частные участники в Python - PullRequest
61 голосов
/ 14 января 2010

Как я могу сделать методы и члены данных приватными в Python? Или Python не поддерживает частных пользователей?

Ответы [ 9 ]

74 голосов
/ 14 января 2010

9,6. Частные переменные

«Частные» переменные экземпляра, которые недоступен, кроме как изнутри объект, не существует в Python. Тем не менее, существует соглашение, которое сопровождается большей частью кода Python: имя с префиксом подчеркивания (например, _spam) следует рассматривать как непубличную часть API (будь то это функция, метод или данные членом). Это следует считать детали реализации и при условии изменить без уведомления.

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

Итак, например ,

class Test:
    def __private_symbol(self):
        pass
    def normal_symbol(self):
        pass

print dir(Test)

выведет:

['_Test__private_symbol', 
'__doc__', 
'__module__', 
'normal_symbol']

__private_symbol следует рассматривать как закрытый метод, но он все равно будет доступен через _Test__private_symbol.

34 голосов
/ 14 января 2010

Другие ответы содержат технические детали. Я хотел бы подчеркнуть разницу в философии между Python, с одной стороны, и такими языками, как C ++ / Java (который, я полагаю, вы знакомы, основываясь на вашем вопросе).

Общее отношение в Python (и в этом отношении к Perl) заключается в том, что «конфиденциальность» атрибута является запросом к программисту, а не ограждением из колючей проволоки со стороны компилятора / интерпретатора. Идея хорошо изложена в этом письме и часто упоминается как «Мы ​​все взрослые по обоюдному согласию», поскольку она «предполагает», что программист достаточно ответственен, чтобы не вмешиваться во внутренности. Начальные подчеркивания служат вежливым сообщением о том, что атрибут является внутренним.

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

6 голосов
/ 14 января 2010

Нет никаких других механизмов защиты доступа в Python private. В руководстве по стилю Python задокументировано соглашение, указывающее пользователям вашего класса, что им не следует обращаться к определенному атрибуту.

  • _single_leading_underscore: слабый индикатор «внутреннего использования». Например. from M import * не импортирует объекты, имя которых начинается с подчеркивания.

  • single_trailing_underscore_: используется по соглашению, чтобы избежать конфликтов с ключевым словом Python, например, Tkinter.Toplevel(master, class_='ClassName')

  • __ double_leading_underscore: при именовании атрибута класса вызывает искажение имени (внутри класса FooBar __boo становится _FooBar__boo; см. Ниже).

6 голосов
/ 14 января 2010

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

Погружение в Python

5 голосов
/ 27 декабря 2013

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

class Person(object):

    def __priva(self):
        print "I am Private"

    def publ(self):
        print " I am public"

    def callpriva(self):
        self.__priva()

Сейчас, когда мы выполним:

>>> p = Person()
>>> p.publ()
 I am public
>>> p.__priva()
Traceback (most recent call last):
  File "", line 1, in 
    p.__priva()
AttributeError: 'Person' object has no attribute '__priva'
​#Explanation   : You can see  here we are not able to fetch that private method directly.
>>> p.callpriva()
I am Private
#​Explanation  : Here we can access private method inside class​

Тогда как кто-то может получить доступ к этой переменной ???
Вы можете сделать как:

>>>p._Person__priva
I am Private

Ух, на самом деле, если Python получает любую переменную, начинающуюся с двойного подчеркивания, «переводится» путем добавления в начало одного подчеркивания и имени класса:

Примечание: Если вы не хотите, чтобы это имя изменялось, но вы все еще хотите отправить сигнал об удалении других объектов, вы можете использовать одно начальное подчеркивание, при этом начальное подчеркивание не импортируется. с помеченным импортом (из модуля импорта *)
Пример:

#test.py
def hello():
    print "hello"
def _hello():
    print "Hello private"

#----------------------
#test2.py
from test import *
print hello()
print _hello()

выход ->

hello
Traceback (most recent call last):
  File "", line 1, in 
NameError: name '_hello' is not defined

Теперь, если мы будем вызывать _hello вручную.

#test2.py
from test import _hello , hello
print hello()
print _hello()

выход ->

hello
hello private

Наконец: Python не имеет эквивалентной поддержки конфиденциальности, хотя и двойные начальные подчеркивания в некоторой степени дают вам два уровня конфиденциальности

2 голосов
/ 12 февраля 2017

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

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

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

В спецификации модуля описаны все функции, которые должны быть видны разработчику клиента. При работе с большими проектами и командами разработчиков программного обеспечения фактическая реализация модуля должна ВСЕГДА оставаться скрытой от тех, кто его использует - это черный ящик с интерфейсом для внешнего мира. Для пуристов OOD я считаю, что технические термины - это «разъединение» и «согласованность». Пользователь модуля должен знать только методы интерфейса, не обременяя себя деталями реализации.

Модуль НИКОГДА не следует менять без предварительного изменения его базового спецификационного документа, что может потребовать проверки / одобрения в некоторых организациях до изменения кода.

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

Затем я начинаю кодирование с написания различных классов и методов, но без функциональных тел - просто нулевых операторов print, таких как "print ()" - достаточно, чтобы модуль мог компилироваться без синтаксических ошибок. Когда этот шаг завершен, я компилирую завершенный нулевой модуль - это моя спецификация. Если бы я работал в команде проекта, я бы представил эту спецификацию / интерфейс для обзора и комментариев, прежде чем приступить к выделению тела.

Я уточняю тела каждого метода по одному и компилирую соответственно, гарантируя, что синтаксические ошибки будут исправлены немедленно на лету. Это также хорошее время, чтобы начать писать временную «основную» секцию выполнения внизу, чтобы протестировать каждый метод при его кодировании. Когда кодирование / тестирование завершено, весь тестовый код закомментирован до тех пор, пока он вам не понадобится снова, если потребуется обновление.

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

PS: задолго до начала времени я работал в оборонном аэрокосмическом сообществе, и мы сделали несколько довольно крутых вещей, но такие вещи, как проприетарные алгоритмы и логика управления чувствительными системами, были надежно зашифрованы и зашифрованы в супер-защищенных библиотеках программного обеспечения. У нас был доступ к интерфейсам модуля / пакета, но НЕ к телам реализации черного ящика Был инструмент управления документами, который обрабатывал все проекты системного уровня, спецификации программного обеспечения, исходный код и записи тестов - все это было синхронизировано вместе. Правительство предъявляло строгие требования к программному обеспечению качества. Кто-нибудь помнит язык под названием "Ада"? Вот сколько мне лет!

2 голосов
/ 03 февраля 2017

Это может сработать:

import sys, functools

def private(member):
    @functools.wraps(member)
    def wrapper(*function_args):
      myself = member.__name__
      caller = sys._getframe(1).f_code.co_name
      if (not caller in dir(function_args[0]) and not caller is myself):
         raise Exception("%s called by %s is private"%(myself,caller))
      return member(*function_args)
    return wrapper

class test:
   def public_method(self):
      print('public method called')

   @private
   def private_method(self):
      print('private method called')

t = test()
t.public_method()
t.private_method()
0 голосов
/ 22 мая 2019

Я использую Python 2.7 и 3.5. Я написал этот код:

class MyOBject(object):
    def __init__(self):
        self.__private_field = 10


my_object = MyOBject()
print(my_object.__private_field)

запустил его и получил:

AttributeError: у объекта 'MyOBject' нет атрибута '__private_field'

Пожалуйста, смотрите: https://www.tutorialsteacher.com/python/private-and-protected-access-modifiers-in-python

0 голосов
/ 21 октября 2015

если вы хотите сделать методы или члены данных приватными в Python, используйте __setattr __

class Number:
    def __init__(self,value):
        self.my_private = value

    def __setattr__(self, my_private, value):
        # the default behavior
        # self.__dict__[my_private] = value
        raise Exception("can't access private member-my_private")


def main():
    n = Number(2)
    print(n.my_private)

if __name__ == '__main__': 
    main()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...