Ответ
Python — полностью объектно-ориентированный язык, и его синтаксис и семантика предоставляют элегантные способы реализации четырех основных принципов ООП.
1. Инкапсуляция (Encapsulation) Сокрытие внутреннего состояния объекта и предоставление контролируемого доступа через публичные методы. В Python это соглашение, а не строгое правило.
class TemperatureSensor:
def __init__(self):
# Защищенный атрибут (соглашение: один underscore)
self._current_temperature = 0.0
# Приватный атрибут (name mangling: два underscore)
self.__calibration_factor = 1.02
# Публичный метод-геттер для контролируемого доступа
def get_temperature(self):
# Внутренняя логика, например, чтение с датчика и калибровка
raw_reading = self._read_hardware()
self._current_temperature = raw_reading * self.__calibration_factor
return self._current_temperature
# Защищенный метод для внутреннего использования
def _read_hardware(self):
# Симуляция чтения с аппаратного датчика
return 25.5
# Публичный метод-сеттер с валидацией
def set_calibration(self, factor):
if 0.5 < factor < 1.5:
self.__calibration_factor = factor
else:
raise ValueError("Calibration factor out of range")
sensor = TemperatureSensor()
print(sensor.get_temperature()) # OK: 26.01
# print(sensor.__calibration_factor) # AttributeError
print(sensor._TemperatureSensor__calibration_factor) # Доступ с name mangling (но не нужно так делать)
sensor.set_calibration(1.1) # OK
2. Наследование (Inheritance) Создание нового класса на основе существующего с возможностью переопределения или расширения функциональности. Python поддерживает множественное наследование.
class Vehicle:
def __init__(self, make, model):
self.make = make
self.model = model
self._speed = 0
def move(self):
return f"The {self.make} {self.model} is moving."
class ElectricCar(Vehicle): # ElectricCar наследует от Vehicle
def __init__(self, make, model, battery_capacity):
# Вызов конструктора родительского класса
super().__init__(make, model)
self.battery_capacity = battery_capacity
self._charge_level = 100
# Переопределение метода родителя
def move(self):
if self._charge_level > 0:
self._charge_level -= 5
return f"The {self.make} {self.model} moves silently. Charge: {self._charge_level}%"
else:
return "Battery depleted!"
# Новый метод, специфичный для дочернего класса
def recharge(self):
self._charge_level = 100
my_tesla = ElectricCar("Tesla", "Model S", 100)
print(my_tesla.move()) # Вызов переопределенного метода
print(isinstance(my_tesla, Vehicle)) # True
print(issubclass(ElectricCar, Vehicle)) # True
3. Полиморфизм (Polymorphism) Возможность объектов с разной внутренней структурой иметь одинаковый интерфейс. В Python это реализуется через утиную типизацию (duck typing).
class PDFExporter:
def export(self, data):
# Логика генерации PDF
return "PDF file generated"
class CSVExporter:
def export(self, data):
# Логика генерации CSV
return "CSV file generated"
class ReportGenerator:
def generate_report(self, data, exporter): # exporter — любой объект с методом export()
# Полиморфный вызов: не важно, какой именно экспортер,
# главное, что у него есть метод export.
result = exporter.export(data)
print(result)
# Использование
generator = ReportGenerator()
data = {"sales": [100, 200, 150]}
generator.generate_report(data, PDFExporter()) # Выведет: PDF file generated
generator.generate_report(data, CSVExporter()) # Выведет: CSV file generated
4. Абстракция (Abstraction) Сокрытие сложной реализации и предоставление простого интерфейса. Достигается через абстрактные базовые классы (ABC).
from abc import ABC, abstractmethod
import numpy as np
class MLModel(ABC):
"""Абстракция модели машинного обучения."""
@abstractmethod
def fit(self, X, y):
"""Обучить модель на данных X, y."""
pass
@abstractmethod
def predict(self, X):
"""Сделать предсказание для данных X."""
pass
# Абстрактное свойство
@property
@abstractmethod
def is_fitted(self):
pass
class LinearRegressionModel(MLModel):
"""Конкретная реализация абстракции."""
def __init__(self):
self._coef = None
self._intercept = None
self._fitted = False
def fit(self, X, y):
# Реальная, сложная реализация метода fit
X_with_intercept = np.c_[np.ones(X.shape[0]), X]
coeffs = np.linalg.pinv(X_with_intercept.T @ X_with_intercept) @ X_with_intercept.T @ y
self._intercept, *self._coef = coeffs
self._fitted = True
def predict(self, X):
if not self._fitted:
raise ValueError("Model is not fitted yet.")
return self._intercept + X @ self._coef
@property
def is_fitted(self):
return self._fitted
# Пользователь работает с абстракцией, не зная деталей реализации.
model = LinearRegressionModel()
model.fit(X_train, y_train)
predictions = model.predict(X_test)
Эти принципы в Python реализованы гибко, что позволяет писать выразительный и эффективный объектно-ориентированный код.