6.1. Инкапсуляция
Инкапсуляция — это объединение данных (атрибутов) и методов, работающих с этими данными, внутри одной сущности (класса/объекта). Также инкапсуляция подразумевает сокрытие внутреннего устройства объекта и предоставление контролируемого доступа к его данным.
Цели инкапсуляции:
- Защита данных от случайного или некорректного изменения извне.
- Упрощение интерфейса объекта (пользователю не нужно знать детали реализации).
- Повышение модульности и гибкости (внутреннюю реализацию можно менять, не затрагивая код, использующий объект, если интерфейс сохранен).
Уровни Доступа в Python (Соглашения)
В Python нет строгих модификаторов доступа (public
, private
, protected
), как в некоторых других языках (Java, C++). Вместо этого используются соглашения об именовании:
- Public (Публичный): Атрибуты и методы без префикса подчеркивания (
my_attribute
,my_method()
). Доступны отовсюду. Это стандартный вариант. - Protected (Защищенный): Имена с одним префиксом подчеркивания (
_protected_attribute
,_protected_method()
). Это сигнал для других разработчиков, что данный атрибут/метод предназначен для внутреннего использования внутри класса или его дочерних классов, и его не следует использовать напрямую извне. Однако технически Python не запрещает доступ к нему. - Private (Приватный): Имена с двумя префиксами подчеркивания (
__private_attribute
,__private_method()
). Python применяет механизм “искажения имен” (name mangling): имя автоматически изменяется на_ClassName__private_name
. Это затрудняет случайный доступ извне и предотвращает конфликты имен в дочерних классах, но не является настоящим сокрытием данных. Доступ все еще возможен по искаженному имени.
class MyClass:
def __init__(self):
self.public_var = "Я публичный"
self._protected_var = "Я защищенный (по соглашению)"
self.__private_var = "Я приватный (искажение имени)"
def public_method(self):
print("Публичный метод")
self._protected_method()
self.__private_method()
def _protected_method(self):
print("Защищенный метод")
def __private_method(self):
print("Приватный метод")
obj = MyClass()
# Доступ к public
print(obj.public_var) # Я публичный
obj.public_method() # Вызывает все три
# Доступ к protected (технически возможен, но не рекомендуется)
print(obj._protected_var) # Я защищенный (по соглашению)
obj._protected_method() # Защищенный метод
# Попытка доступа к private напрямую вызовет ошибку
print(obj.__private_var) # AttributeError
obj.__private_method() # AttributeError
# Доступ к private через искаженное имя (не рекомендуется!)
print(obj._MyClass__private_var) # Я приватный (искажение имени)
obj._MyClass__private_method() # Приватный метод
Геттеры и Сеттеры
Традиционный способ управления доступом к атрибутам — через методы-геттеры (для получения значения) и сеттеры (для установки значения с возможной проверкой). В Python более “питоничным” способом являются свойства.
6.2. Абстракция
Абстракция — это процесс выделения наиболее важных характеристик объекта и игнорирования несущественных деталей. В ООП абстракция позволяет создавать классы, которые представляют общую концепцию, не вдаваясь в детали конкретной реализации.
Пользователю класса предоставляется только необходимый интерфейс (набор публичных методов и атрибутов), а сложность внутренней работы скрыта.
Абстрактные Базовые Классы (ABC - Abstract Base Classes)
В Python для формализации абстракции используется модуль abc
. Абстрактный класс не может быть инстанциирован (нельзя создать его объект) и может содержать абстрактные методы.
- Абстрактный метод: Метод, объявленный в абстрактном классе (с декоратором
@abstractmethod
), но не имеющий реализации. Все дочерние классы обязаны переопределить и реализовать все абстрактные методы родителя, иначе они тоже станут абстрактными.
from abc import ABC, abstractmethod
# Абстрактный базовый класс
class Shape(ABC):
def __init__(self, name):
self.name = name
@abstractmethod # Декоратор для объявления абстрактного метода
def area(self):
pass # Нет реализации
@abstractmethod
def perimeter(self):
pass
def describe(self): # Обычный метод
print(f"Это фигура: {self.name}")
# Попытка создать объект абстрактного класса вызовет ошибку
# shape = Shape("Фигура") # TypeError: Can't instantiate abstract class Shape...
# Конкретный дочерний класс, реализующий АБСТРАКТНЫЕ методы
class Square(Shape):
def __init__(self, side):
super().__init__("Квадрат")
self.side = side
def area(self): # Реализация обязательна
return self.side * self.side
def perimeter(self): # Реализация обязательна
return 4 * self.side
# Другой конкретный класс
class Circle(Shape):
pi = 3.14159
def __init__(self, radius):
super().__init__("Круг")
self.radius = radius
def area(self):
return self.pi * (self.radius ** 2)
def perimeter(self):
return 2 * self.pi * self.radius
# Теперь можно создавать объекты дочерних классов
sq = Square(5)
ci = Circle(3)
sq.describe() # Это фигура: Квадрат (унаследованный метод)
print(f"Площадь квадрата: {sq.area()}") # 25
print(f"Периметр квадрата: {sq.perimeter()}") # 20
ci.describe() # Это фигура: Круг
print(f"Площадь круга: {ci.area():.2f}") # 28.27
print(f"Периметр круга: {ci.perimeter():.2f}") # 18.85
Абстрактные классы помогают определить общий интерфейс для группы классов и гарантировать, что все подклассы будут иметь необходимый набор методов.
〰〰〰 𓆝 𓆟 𓆞 𓆝 𓆟 𓆝 𓆟 𓆞 〰〰〰