Классы питон приватные методы

Приватность методов в Python

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

В качестве примера возьмем следующий код:

class MyClass: def myPublicMethod(self): print('public method') def __myPrivateMethod(self): print('this is private!!') obj = MyClass() obj.myPublicMethod()

Здесь мы создали класс с публичным методом myPublicMethod() и приватным методом __myPrivateMethod() . При попытке вызвать приватный метод, мы столкнемся с ошибкой AttributeError , которая говорит о том, что у экземпляра класса MyClass нет атрибута __myPrivateMethod .

На первый взгляд, все выглядит ожидаемо — мы не можем вызвать приватный метод. Однако, при использовании функции dir() на объекте, мы обнаружим новый «магический» метод, который Python создает автоматически для всех ваших «приватных» методов.

Название этого нового метода всегда начинается с подчеркивания, за которым следует имя класса и имя метода.

obj._MyClass__myPrivateMethod()

Таким образом, «приватность» методов в Python является относительной. Несмотря на то, что Python предоставляет возможность в некоторой степени инкапсулировать методы и переменные, полностью сделать их приватными не удается. На самом деле, Python использует механизм под названием «name mangling» для изменения имени «приватного» метода, чтобы предотвратить его случайное вызывание.

Этот механизм не предназначен для создания секретности или безопасности, а служит для предотвращения ошибок при работе с методами и переменными, которые должны быть использованы только внутри класса.

Источник

Режимы доступа public, private, protected. Сеттеры и геттеры

На прошлых занятиях мы научились с вами создавать экземпляры классов и объявлять в них атрибуты и методы. Пришла пора сделать следующий шаг и познакомиться с механизмом ограничения доступа к данным и методам класса извне. Это основа механизма инкапсуляции.

Давайте предположим, что мы описываем класс представления точки на плоскости:

class Point: def __init__(self, x=0, y=0): self.x = x self.y = y

Когда создается экземпляр этого класса:

то имеется полный доступ ко всем его локальным атрибутам:

а, значит, их всегда можно изменить через ссылку pt:

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

  • attribute (без одного или двух подчеркиваний вначале) – публичное свойство (public);
  • _attribute (с одним подчеркиванием) – режим доступа protected (служит для обращения внутри класса и во всех его дочерних классах)
  • __attribute (с двумя подчеркиваниями) – режим доступа private (служит для обращения только внутри класса).
class Point: def __init__(self, x=0, y=0): self._x = x self._y = y

Так реализуется режим protected в Python. Если кто из вас программирует на других языках, например, С++ или Java, то сейчас ожидают, что мы не сможем обращаться к свойствам _x и _y через ссылку pt, так как они определены как защищенные (protected). Давайте проверим и попробуем вывести их в консоль:

Как видим, никаких ошибок не возникает и все работает так, словно это публичные свойства экземпляра класса. Но тогда зачем нам писать это нижнее подчеркивание, если оно не играет никакой роли? Одна роль у этого префикса все-таки есть: нижнее подчеркивание должно предостерегать программиста от использования этого свойства вне класса. Впоследствии это может стать причиной непредвиденных ошибок. Например, изменится версия класса и такое свойство может перестать существовать, т.к. никто не предполагал доступа к нему извне. Так что, к таким атрибутам лучше не обращаться напрямую – одно нижнее подчеркивание указывает нам, что это внутренние, служебные переменные. Давайте теперь посмотрим, как работает режим доступа private. Пропишем у локальных свойств два подчеркивания:

class Point: def __init__(self, x=0, y=0): self.__x = x self.__y = y

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

def set_coord(self, x, y): self.__x = x self.__y = y

Как видите, никаких ошибок не возникает и чтобы убедиться в изменении локальных приватных свойств, определим еще один метод:

def get_сoord(self): return self.__x, self.__y

После запуска программы видим измененные координаты точки. В результате, мы с вами определили два вспомогательных метода: set_coord и get_coord, через которые предполагается работа с защищенными данными класса. Такие методы в ООП называются сеттерами и геттерами или еще интерфейсными методами. Зачем понадобилось в классах создавать приватные атрибуты да еще и определять дополнительно методы для работы с ними извне. Я об этом уже говорил на самом первом занятии по ООП, когда объяснял принцип инкапсуляции. Но, скажу еще раз. Класс в ООП следует воспринимать как некое единое целое, и чтобы случайно или намеренно не нарушить целостность работы алгоритма внутри этого класса, то следует взаимодействовать с ним только через публичные свойства и методы. В этом суть принципа инкапсуляции. Опять же, представьте автомобиль, в котором согласованно работают тысячи узлов. А управление им предполагается только через разрешенные интерфейсы: руль, коробка передач, педали газа и тормоза и т.п. Если во время движения вмешиваться напрямую в его узлы, например, будем на ходу спускать воздух из шин, то, наверное, ничего хорошего не получится. То же самое, можно сказать и о программисте, который намеренно обходит запрет и обращается к скрытым атрибутам класса напрямую, а не через сеттеры или геттеры. Так делать не нужно. Назначение интерфейсных методов не только передавать значения между приватными атрибутами класса, но и проверять их корректность. Например, в нашем случае координаты должны быть числами. Поэтому, прежде чем обновлять значения переменных, следует проверить их тип данных. Для этого можно воспользоваться функцией type и записать сеттер следующим образом:

def set_coord(self, x, y): if type(x) in (int, float) and type(y) in (int, float): self.__x = x self.__y = y else: raise ValueError("Координаты должны быть числами")

Здесь мы проверяем, что обе переданные переменные x и y должны иметь тип int или float и только после этого приватным атрибутам экземпляра класса присваиваются новые значения. Иначе, генерируется исключение ValueError. Об исключениях мы с вами еще будем говорить. Теперь, если передавать недопустимые значения координат:

то увидим ошибку ValueError. Продолжим совершенствовать наш класс Point и добавим приватный метод для проверки корректности координат. Приватный метод объявляется также как и приватная переменная – двумя подчеркиваниями и, кроме того, сделаем его методом уровня класса (о декораторе classmethod мы с вами говорили на предыдущем занятии):

@classmethod def __check_value (cls, x): return type(x) in (int, float)
def __init__(self, x=0, y=0): self.__x = self.__y = 0 if self.__check_value (x) and self.__check_value (y): self.__x = x self.__y = y def set_coord(self, x, y): if self.__check_value (x) and self.__check_value (y): self.__x = x self.__y = y else: raise ValueError("Координаты должны быть числами")

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

то среди прочих мы увидим, следующие: ‘_Point__x’, ‘_Point__y’ Это и есть кодовые имена приватных атрибутов, к которым мы можем обратиться через ссылку pt:

print(pt._Point__x, pt._Point__y)

и менять их. Однако, так делать крайне не рекомендуется и двойное подчеркивание должно сигнализировать программисту, что работать с такими атрибутами нужно только через разрешенные интерфейсные методы. Иначе, возможны непредвиденные ошибки. Если у вас появилась необходимость лучше защитить методы класса от доступа извне, то это можно сделать с помощью модуля accessify. Для его установки нужно выполнить команду: pip install accessify И, затем, импортировать из него два декоратора:

from accessify import private, protected

Далее, нужный декоратор просто применяем к методу и он становится либо приватным (private), либо защищенным (protected):

@private @classmethod def check_value(cls, x): return type(x) in (int, float)

Источник

Private Methods in Python

Encapsulation is one of the fundamental concepts in object-oriented programming (OOP) in Python. It describes the idea of wrapping data and the methods that work on data within one unit. This puts restrictions on accessing variables and methods directly and can prevent the accidental modification of data. A class is an example of encapsulation as it encapsulates all the data that is member functions, variables, etc. Now, there can be some scenarios in which we need to put restrictions on some methods of the class so that they can neither be accessed outside the class nor by any subclasses. To implement this private methods come into play.

P rivate functions in Python

Consider a real-life example, a car engine, which is made up of many parts like spark plugs, valves, pistons, etc. No user uses these parts directly, rather they just know how to use the parts which use them. This is what private methods are used for. It is used to hide the inner functionality of any class from the outside world. Private methods are those methods that should neither be accessed outside the class nor by any base class. In Python, there is no existence of Private methods that cannot be accessed except inside a class. However, to define a private method prefix the member name with the double underscore__”. Note: The __init__ method is a constructor and runs as soon as an object of a class is instantiated.

Источник

Читайте также:  Python распознавание изображений пример
Оцените статью