#python #private
#python #Частное
Вопрос:
Я знаю, что в Python нет такого понятия, как true private, потому что иногда вам нужно следовать:
- запретить пользователям вызывать некоторые методы или предупреждать их, когда они это делают, но разрешить их вызывать из других модулей
- определите, где используются эти методы, и выведите предупреждение на консоль или даже исключение, это позволит вам начать помечать методы как частные, не нарушая существующий код.
- скрыть частные методы из автозаполнения IDE (необязательно) — возможно, используя одно подчеркивание перед его именем. Теперь мне интересно, нашел ли кто-нибудь красивый способ добиться такого поведения, может быть, тот, который использует
annotations
?
Пожалуйста, помните, что это должно работать с существующей кодовой базой, поэтому оно должно поддерживать постепенную переработку существующего кода.
Последний пункт почти решен, единственный вопрос в том, должен ли я использовать одно подчеркивание или два подчеркивания?
Комментарии:
1. Как вы проводите различие в # 1? # 2 будет зависеть от IDE. # 3 может быть возможным, но будет генерировать фиктивные предупреждения (если вы не потрудитесь отличить «законных» абонентов от остальных, и даже скорее всего, это не будет идеальным в любом смысле этого слова) и в любом случае звучит как устаревание, а не конфиденциальность. Почему бы просто не изменить имя? Добавьте символ подчеркивания, ничто не говорит «частный», как это.
2. Просто используйте одно подчеркивание — искажение имени, вызванное двойным подчеркиванием, вызовет гораздо больше головной боли, чем решит.
Ответ №1:
У Python есть философия «согласия взрослых»: префиксные методы с подчеркиванием, чтобы пометить их как частные. Не вызывайте никаких методов с начальным подчеркиванием извне. Если вы это сделаете, вы сами по себе. Вы можете это сделать, но вас предупредили.
Чтобы внедрить это преобразование в существующую базу кода, переименуйте исходные методы в имена с начальным подчеркиванием и добавьте оболочку с исходным именем, которая выдает предупреждение.
Ваша IDE должна иметь настраиваемое автозаполнение. Если нет, используйте Emacs 🙂
Комментарии:
1. @Paul: Часть Emacs была скорее шуткой. Мне действительно и честно все равно, что другие люди используют для редактирования своего кода. vi тоже в порядке. 🙂
Ответ №2:
Скрытие от автозаполнения будет полностью зависеть от вашего редактора и от того, как он обрабатывает автозаполнение. Мой редактор не выполняет автозаполнение, поэтому мне не нужно его использовать.
Стандартное соглашение python — это префикс и подчеркивание имени метода. Это сообщает пользователю, что метод является частным и его не следует использовать.
Вы можете использовать двойные подчеркивания перед именем метода; это вызовет искажение имени.
Подробности см. в разделе 9.7 на этой странице: http://docs.python.org/tutorial/classes.htm .
Но это все еще не приватно; его можно вызвать.
Что касается исключений, посмотрите на объект проверки и информацию о фрейме. На этом сайте есть множество вопросов и ответов по этому поводу.
tl; dr Вы не можете сделать что-либо закрытым, но вы можете усложнить поиск
Комментарии:
1. Двойные подчеркивания перед именем вызывают искажение имени. Двойные подчеркивания перед и после имени — это зарезервированные имена, которые не должны использоваться (за исключением предопределенных, конечно).
Ответ №3:
Возможно, определите свои частные методы во внутреннем классе и получите к нему внутренний доступ, используя self._private.method
:
class PublicObject(object):
class PrivateObject(object):
def __init__(self, public):
self.public = public
def private1(self):
print "a private method, not visible outside the public wrapper on", id(self.public)
def __init__(self):
self._private = self.PrivateObject(self)
def public1(self):
print "a public method, which invokes a private one"
return self._private.private1()
a = PublicObject()
print dir(a) # only shows public1, not private1; won't show private1 in most IDEs autocomplete
a.public1()
a.private1() # raises an exception
a._private.private1() # still possible to call private methods, but obvious when you are doing so
Если вы хотите, чтобы ProtectedObject отображался в цепочке наследования, создайте аналогичный _protected
атрибут и используйте __getattr__
для доступа к атрибутам и методам super(PublicObject,self.public)._protected
.
Кстати, то, о чем вы спрашиваете, действительно выходит за рамки философии Python, и добавление этого косвенного обращения через составной объект приведет к снижению производительности.
Ответ №4:
Вы можете украсить частные методы вызовом warnings.warn
.
Я не уверен, что вы имеете в виду, запрещая людям, но позволяя модулям вызывать методы. Является ли различие в том, что одно происходит в интерактивном приглашении, а другое — нет? Если это так, вы можете проверить, запускается ли python из интерактивного приглашения, проверив значение sys.path[0]
.
Когда python запускает скрипт, sys.path[0]
он равен каталогу скрипта. Когда python запускает интерактивный сеанс, sys.path[0]
устанавливается пустая строка ''
. Итак, чтобы предупредить людей, но не скрипты, вы могли бы сделать
import warnings
import functools
def warn_private(func):
if not sys.path[0]:
@functools.wraps(func)
def wrapper(self,*args,**kwargs):
warnings.warn('{f} is private'.format(f=func.__name__))
return func(self,*args,**kwargs)
return wrapper
else:
return func
class Foo(object):
@warn_private
def _bar(self):
pass
Комментарии:
1. Разве это не будет предупреждать даже о законных внутренних вызовах _bar изнутри Foo?
2. @PaulMcGuire: На ваш вопрос отвечает вторая часть моего ответа. Поскольку я опубликовал сообщение в два этапа, возможно, его не было, когда вы опубликовали комментарий.
3. @unutbu: Извините за это. Я надеялся, что вы этого не видели 🙂