- PVSM.RU - https://www.pvsm.ru -
В этой заметке я хотел бы привести краткое описание методов регулирования доступа к атрибутам класса в питоне с помощью декораторов и с помощью присвоения специальным образом имен атрибутам в соответсвии с хорошим стилем программирования, описанным в PEP 8 [1]. Статья написана на основе обсуждений данной темы на StackOverflow.com [2], нескольких мануалов и личного опыта автора.
Занимаясь написанием программ, выполняющие научные расчеты, я перешел с c++
на питон, чтобы использовать всю мощь библиотек, к которым относятся numpy, scipy, matplotlib, pyquante и прочие, распространяющиеся под свободной лицензией и находящихся в избытке на github [3]. Однако, на начальном этапе такого перехода у меня возник дискомфорт, связанный с отсутствием таких привычных в с++ модификаторов доступа, как privat
, public
и protected
, а также методов get()
и set()
, что и побудило меня написать эту заметку. На StackOverflow [2] первое, что бросается в глаза при обсуждении отсутствия модификаторов доступа в питоне, — это всеобщее согласие с большой долей ответственности разработчика при написании кода, которая побуждает его соблюдать хороший стиль программирования, описанный в PEP 8 [1]. Проблема заключается в том, что в питоне всегда можно получить доступ к любому атрибуту любого класса, однако, согласно хорошему стилю, такой доступ пользователями библиотеки классов должен быть осуществлен не прямо, а с помощью некоторого интерфейса и только там, где это нужно и предусмотрено разработчиком.
Рассмотрим класс, содержащий атрибут attr
:
class MyClass:
def __init__(self):
self.attr = 0
Существует очевидная возможность доступа к атрибуту напрямую после создания объекта класса:
a=Class()
a.attr
Этим способом обращения лучше не злоупотреблять. Для того, чтобы имитировать наличие модификатора доступа privat, можно использовать подчеркивание в начале всех имен атрибутов:
class MyClass:
def __init__(self):
self._attr = 0
Конечно, в этом случае к атрибуту можно обратиться извне класса как:
a._attr
Но каждый раз видя этот код вы будете знать, что: а) осуществляется обращения к атрибуту объекта а
и б) ваш код не соответствует хорошему стилю программирования, поскольку атрибут этого класса с таким именем не предусматривает, что к нему будут обращаться вне определения класса.
Если все же есть необходимость предоставить пользователю доступ к атрибуту данного класса, лучше использовать декоратор @property
. Например:
class MyClass:
def __init__(self):
self.attr = 0
@property
def attr(self):
return self._attr
Теперь обращение к атрибуту извне класса может быть осуществлено привычным нам способом:
a.attr
В функцию attr(self)
можно вложить дополнительную функциональность, обрабатывая определенным образом данные. Например можно сделать так, чтобы она возвращала только целую часть числа, модуль и т. д. В эту функцию можно также передать аргумент, с помощью которого управлять выводом значения self._attr
, получая желаемый результат. Обрабатывая список аргументов этой функции, можно сделать что-то вроде ее перегрузки. Например, если переменная self._attr
представлена массивом, то можно реализовать эту функцию так, что в случае обращения в виде a.attr
мы получим весь массив, а в случае обращения a.attr(j)
— один из его элементов.
Отметим важную деталь, что в данном случае у нас нет никакой возможности изменить значение переменно self._attr извне определения класса, не нарушая при этом хорошего стиля программирования. Другими словами, мы можем это сделать так:
a._attr = 0
Но не можем так:
a.attr = 0
Чтобы вторая опция стала доступной, существует другой декоратор @setter
. Ниже приведен пример его использования:
class MyClass:
def __init__(self):
self.attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self,value):
self._attr = value
Вторым способом имитации модификатора доступа privat
является присвоение имен атрибутам, начинающихся двойным подчеркиванием self.__attr (но не заканчивающихся! — такие имена, как правило, зарезервированы системой). В этом случае будет задействован так называемый name mangling, который заключается в том, что интерпретатор питона автоматически переименовывает атрибут self.__attr
в self._classname__attr
, где classname
— имя текущего класса. В этом случае нет возможности обратиться к атрибуту даже таким варварским методом, как а.__attr
. Внутри определения класса этот атрибут можно вызвать просто как self.__attr
. Для осуществления доступа к таким именам извне часто используют встроенные функции __getattr__()
, __setattr__()
и зарезервированную переменную __dict__
.
Описанные выше методы дают очень широкий спектр возможностей для управления доступом к атрибутам класса, вполне восполняющий отсутствие специальных модификаторов.
Автор: freude
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/37176
Ссылки в тексте:
[1] PEP 8 : http://www.python.org/dev/peps/pep-0008/#naming-conventions
[2] StackOverflow.com: http://stackoverflow.com
[3] github: http://github.com
[4] Источник: http://habrahabr.ru/post/184340/
Нажмите здесь для печати.