Python class protected method

Python — Public, Protected, Private Members

Classical object-oriented languages, such as C++ and Java, control the access to class resources by public, private, and protected keywords. Private members of the class are denied access from the environment outside the class. They can be handled only from within the class.

Public Members

Public members (generally methods declared in a class) are accessible from outside the class. The object of the same class is required to invoke a public method. This arrangement of private instance variables and public methods ensures the principle of data encapsulation.

All members in a Python class are public by default. Any member can be accessed from outside the class environment.

class Student: schoolName = 'XYZ School' # class attribute def __init__(self, name, age): self.name=name # instance attribute self.age=age # instance attribute 

You can access the Student class’s attributes and also modify their values, as shown below.

std = Student("Steve", 25) print(std.schoolName) #'XYZ School' print(std.name) #'Steve' std.age = 20 print(std.age) 

Protected Members

Protected members of a class are accessible from within the class and are also available to its sub-classes. No other environment is permitted access to it. This enables specific resources of the parent class to be inherited by the child class.

Python’s convention to make an instance variable protected is to add a prefix _ (single underscore) to it. This effectively prevents it from being accessed unless it is from within a sub-class.

class Student: _schoolName = 'XYZ School' # protected class attribute def __init__(self, name, age): self._name=name # protected instance attribute self._age=age # protected instance attribute 

In fact, this doesn’t prevent instance variables from accessing or modifying the instance. You can still perform the following operations:

std = Student("Swati", 25) print(std._name) #'Swati' std._name = 'Dipa' print(std._name) #'Dipa' 

However, you can define a property using property decorator and make it protected, as shown below.

class Student: def __init__(self,name): self._name = name @property def name(self): return self._name @name.setter def name(self,newname): self._name = newname 

Above, @property decorator is used to make the name() method as property and @name.setter decorator to another overloads of the name() method as property setter method. Now, _name is protected.

std = Student("Swati") print(std.name) #'Swati' std.name = 'Dipa' print(std.name) #'Dipa' print(std._name) #'Dipa' 

Above, we used std.name property to modify _name attribute. However, it is still accessible in Python. Hence, the responsible programmer would refrain from accessing and modifying instance variables prefixed with _ from outside its class.

Private Members

Python doesn’t have any mechanism that effectively restricts access to any instance variable or method. Python prescribes a convention of prefixing the name of the variable/method with a single or double underscore to emulate the behavior of protected and private access specifiers.

The double underscore __ prefixed to a variable makes it private. It gives a strong suggestion not to touch it from outside the class. Any attempt to do so will result in an AttributeError:

class Student: __schoolName = 'XYZ School' # private class attribute def __init__(self, name, age): self.__name=name # private instance attribute self.__salary=age # private instance attribute def __display(self): # private method print('This is private method.') std = Student("Bill", 25) print(std.__schoolName) #AttributeError print(std.__name) #AttributeError print(std.__display()) #AttributeError 

Python performs name mangling of private variables. Every member with a double underscore will be changed to _object._class__variable . So, it can still be accessed from outside the class, but the practice should be refrained.

std = Student("Bill", 25) print(std._Student__name) #'Bill' std._Student__name = 'Steve' print(std._Student__name) #'Steve' std._Student__display() #'This is private method.' 

Thus, Python provides conceptual implementation of public, protected, and private access modifiers, but not like other languages like C#, Java, C++.

  • Class Attributes vs Instance Attributes in Python
  • Compare strings in Python
  • Convert file data to list
  • Convert User Input to a Number
  • Convert String to Datetime in Python
  • How to call external commands in Python?
  • How to count the occurrences of a list item?
  • How to flatten list in Python?
  • How to merge dictionaries in Python?
  • How to pass value by reference in Python?
  • Remove duplicate items from list in Python
  • More Python articles

Источник

Режимы доступа 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)

Источник

Читайте также:  Tech Decode
Оцените статью