Ответ
Python является полностью объектно-ориентированным языком, где практически всё — это объект. Он полноценно поддерживает ключевые принципы ООП, но делает это гибко, сочетая их с другими парадигмами.
1. Инкапсуляция
Защита данных объекта от прямого доступа. В Python инкапсуляция реализуется через соглашения об именовании, а не через строгие модификаторы доступа (public
, private
):
_variable
: Защищенный (protected) атрибут. Соглашение о том, что этот атрибут не предназначен для использования вне класса или его наследников.__variable
: Приватный (private) атрибут. Python применяет механизм name mangling (искажение имени), преобразуя__variable
в_ClassName__variable
, что затрудняет случайный доступ извне.
2. Наследование
Механизм, позволяющий создавать новый класс на основе существующего. Python поддерживает как одиночное, так и множественное наследование. Порядок вызова методов из родительских классов определяется алгоритмом MRO (Method Resolution Order).
3. Полиморфизм
Возможность использовать объекты с одинаковым интерфейсом без информации о их конкретном типе. В Python полиморфизм проявляется через:
- Переопределение методов (Method Overriding): Класс-наследник может предоставить свою реализацию метода родительского класса.
- Утиная типизация (Duck Typing): «Если это выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, и есть утка». Если объект имеет нужные методы и атрибуты, он может быть использован в определённом контексте, независимо от его класса.
Пример, иллюстрирующий все принципы:
class Shape:
def __init__(self):
self.__name = "Generic Shape" # Инкапсуляция (приватный атрибут)
def draw(self):
# Базовая реализация
raise NotImplementedError("Subclasses must implement this method")
# Наследование от класса Shape
class Circle(Shape):
def __init__(self, radius):
super().__init__()
self._radius = radius # Инкапсуляция (защищенный атрибут)
# Полиморфизм (переопределение метода)
def draw(self):
return f"Drawing a circle with radius {self._radius}"
class Square(Shape):
def __init__(self, side):
super().__init__()
self._side = side
# Полиморфизм (переопределение метода)
def draw(self):
return f"Drawing a square with side {self._side}"
# Утиная типизация: функция работает с любым объектом, у которого есть метод draw()
def render_shape(shape_obj):
print(shape_obj.draw())
circle = Circle(10)
square = Square(5)
render_shape(circle) # Вывод: Drawing a circle with radius 10
render_shape(square) # Вывод: Drawing a square with side 5