1. Абстрактные классы
Абстрактный класс — это класс, который нельзя использовать для создания объектов напрямую. Он служит шаблоном и задаёт методы, обязательные для реализации в дочерних классах.
from abc import ABC, abstractmethod
class Employee(ABC):
@abstractmethod
def work(self):
pass
class Programmer(Employee):
def work(self):
print("Write code")
p = Programmer()
p.work()
- Класс должен наследоваться от
ABC. - Абстрактные методы помечаются декоратором
@abstractmethod. - Можно совмещать абстрактные и обычные (реализованные) методы.
- Попытка создать
Employee()вызоветTypeError.
| Обычный класс | Абстрактный класс |
|---|---|
| Можно создавать объекты | Создание объектов запрещено |
| Переопределение методов не обязательно | Некоторые методы обязательны к реализации |
| Используется напрямую | Используется как основа для наследования |
2. Документация классов
Docstring пишется сразу под объявлением класса в тройных кавычках. Он описывает назначение класса, атрибуты и методы.
class Book:
"""
Represents a book.
Attributes:
title (str): The title of the book.
author (str): The author of the book.
Methods:
get_info(): Returns a brief description of the book.
"""
def __init__(self, title, author):
self.title = title
self.author = author
def get_info(self):
return f"{self.title} by {self.author}"
print(Book.__doc__)
Рекомендации: перечисляйте атрибуты и методы, кратко описывайте назначение, используйте единый стиль по проекту.
3. Пользовательские исключения
Пользовательские исключения позволяют точно указать причину ошибки и отделить ошибки собственной логики от встроенных.
class AccessDeniedError(Exception):
"""Вызывается, если пользователь слишком молод для доступа."""
pass
def check_age(age):
if age < 18:
raise AccessDeniedError("Access denied: age must be at least 18")
print("Access granted")
try:
check_age(16)
except AccessDeniedError as e:
print("Ошибка:", e)
- Наследуются от
Exceptionили его подклассов, а не отBaseException. - Имена принято заканчивать на
Error. - Могут быть пустыми (
pass) или содержать собственную логику.
Дополнительные поля в исключениях
Дополнительные поля помогают передавать в обработчик контекст ошибки:
class AccessDeniedError(Exception):
def __init__(self, age):
self.age = age
super().__init__(f"Access denied: age {age} is too low")
try:
raise AccessDeniedError(15)
except AccessDeniedError as e:
print("Error:", e)
print("Age:", e.age)
Если исключение относится к конкретному типу ошибки, лучше наследоваться от подходящего встроенного исключения, например ValueError:
class TemperatureTooLowError(ValueError):
pass
4. Магические методы
Магические (dunder) методы управляют поведением объектов во встроенных ситуациях: при сравнении, арифметике, итерации, преобразовании в строку и т.д.
| Выражение | Метод | Назначение |
|---|---|---|
str(obj) | __str__ | Строковое представление |
len(obj) | __len__ | Количество элементов |
obj1 == obj2 | __eq__ | Равенство |
obj1 + obj2 | __add__ | Сложение |
item in obj | __contains__ | Проверка вхождения |
obj() | __call__ | Объект как функция |
bool(obj) | __bool__ | Логическое значение |
5. Методы сравнения и @total_ordering
| Метод | Оператор |
|---|---|
__eq__ | == |
__ne__ | != |
__lt__ | < |
__le__ | <= |
__gt__ | > |
__ge__ | >= |
Достаточно реализовать __eq__ и один из методов сравнения, чтобы сортировка и операторы работали. Декоратор @total_ordering из functools автоматически построит остальные сравнения.
from functools import total_ordering
@total_ordering
class Book:
def __init__(self, title):
self.title = title
def __eq__(self, other):
if not isinstance(other, Book):
return NotImplemented
return self.title == other.title
def __lt__(self, other):
return self.title < other.title
Всегда проверяйте тип other через isinstance и возвращайте NotImplemented, если сравнение невозможно.
6. Индексация и доступ к элементам
| Метод | Назначение | Использование |
|---|---|---|
__getitem__ | Получить элемент по ключу/индексу | value = obj[key] |
__setitem__ | Установить значение по ключу | obj[key] = value |
__contains__ | Проверить наличие элемента | key in obj |
__len__ | Вернуть количество элементов | len(obj) |
Эти методы позволяют создавать объекты, похожие на словари и списки.
7. Арифметические методы
| Метод | Оператор |
|---|---|
__add__ | + |
__sub__ | - |
__mul__ | * |
__truediv__ | / |
__floordiv__ | // |
__mod__ | % |
__pow__ | ** |
Для изменения объекта на месте используются инкрементные методы: __iadd__, __isub__, __imul__ и т.д. Они должны изменять self и возвращать его.
__bool__ и __call__
__bool__ определяет поведение объекта в логических выражениях. Если метод не определён, Python использует __len__ (пустой объект — ложный).
__call__ позволяет обращаться к объекту как к функции: obj(...). Это удобно для конвертеров, счётчиков и декораторов.