← Назад к вопросам
Какие знаешь рекомендации при написании функции?
1.7 Middle🔥 201 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Рекомендации при написании функций
Написание качественных функций - это искусство, которое требует внимания к деталям и глубокого понимания принципов чистого кода. Я поделюсь проверенными рекомендациями из 10+ лет опыта.
1. Одна ответственность (Single Responsibility Principle)
Функция должна делать одно и делать это хорошо:
# Плохо - функция делает слишком много
def process_user_order(user_id, items):
user = get_user_from_db(user_id)
for item in items:
if item["price"] < 0:
return {"error": "Invalid price"}
order = create_order(user, items)
save_order(order)
send_email(user.email, "Order confirmed")
log(f"Order {order.id} created")
return order
# Хорошо - каждая функция имеет одну ответственность
def create_order(user_id: int, items: list) -> Order:
"""Создание заказа после валидации"""
validate_items(items)
user = get_user_from_db(user_id)
return Order.create(user, items)
def validate_items(items: list) -> None:
"""Валидация товаров"""
for item in items:
if item["price"] < 0:
raise ValueError("Invalid price")
2. Чистое имя функции
Имя должно ясно описывать, что делает функция:
# Непонятные имена
def fn(x):
return x * 2
def do_stuff(data):
pass
# Описательные имена
def double_integer(value: int) -> int:
"""Удваивает переданное целое число"""
return value * 2
def calculate_total_price(items: list) -> float:
"""Вычисляет итоговую стоимость товаров с налогом"""
return sum(item.price for item in items) * 1.2
3. Ограничение параметров (максимум 3-4)
Если параметров больше, используй объект:
# Слишком много параметров
def create_report(user_id, start_date, end_date, format, language,
include_charts, include_summary, send_email, email_address):
pass
# Группируем в объект
from dataclasses import dataclass
@dataclass
class ReportConfig:
format: str
language: str
include_charts: bool = True
include_summary: bool = True
send_email: bool = False
email_address: str = ""
def create_report(user_id: int, start_date, end_date,
config: ReportConfig) -> Report:
"""Создание отчёта с указанными параметрами"""
pass
4. Явное лучше неявного
# Неявное поведение
def get_user(user_id):
try:
return User.objects.get(id=user_id)
except:
return None
# Явное поведение с типами
from typing import Optional
def get_user_by_id(user_id: int) -> Optional[User]:
"""Получает пользователя по ID, возвращает None если не найден"""
try:
return User.objects.get(id=user_id)
except User.DoesNotExist:
return None
5. Чистые функции (Pure Functions)
Идеально, когда функция не имеет побочных эффектов:
# Нечистая функция - изменяет внешнее состояние
discount = 0.1
def apply_discount(price):
global discount
discount = 0.2
return price * (1 - discount)
# Чистая функция - нет побочных эффектов
def apply_discount(price: float, discount_rate: float) -> float:
"""Применяет скидку к цене"""
return price * (1 - discount_rate)
6. Обработка ошибок
# Плохо - нет обработки ошибок
def parse_json(data: str) -> dict:
return json.loads(data)
# Хорошо - явная обработка
from typing import Optional
def parse_json(data: str) -> Optional[dict]:
"""Пытается спарсить JSON, возвращает None при ошибке"""
try:
return json.loads(data)
except json.JSONDecodeError as e:
logger.error(f"Failed to parse JSON: {e}")
return None
7. Документация и Type Hints
# Без документации
def calc(a, b):
return a + b
# С документацией
def calculate_total_amount(base_price: float, tax_rate: float) -> float:
"""Вычисляет итоговую сумму с налогом.
Args:
base_price: Базовая цена товара
tax_rate: Налоговая ставка (0.0 - 1.0)
Returns:
Итоговая цена с налогом
Raises:
ValueError: Если цена или налог отрицательные
Example:
calculate_total_amount(100, 0.1) -> 110.0
"""
if base_price < 0 or tax_rate < 0:
raise ValueError("Price and tax rate must be positive")
return base_price * (1 + tax_rate)
8. Избегай магических чисел
# Магические числа
def validate_password(password: str) -> bool:
return len(password) >= 8
# Именованные константы
MIN_PASSWORD_LENGTH = 8
MAX_PASSWORD_LENGTH = 128
def validate_password(password: str) -> bool:
"""Валидирует пароль по стандартам безопасности"""
if len(password) < MIN_PASSWORD_LENGTH:
raise ValueError(f"Password must be at least {MIN_PASSWORD_LENGTH} characters")
if len(password) > MAX_PASSWORD_LENGTH:
raise ValueError(f"Password must not exceed {MAX_PASSWORD_LENGTH} characters")
return True
9. Избегай глубокой вложенности
# Глубокая вложенность - адский код
def process_order(order):
if order:
if order.items:
if order.user:
if order.user.is_active:
if order.total > 0:
save_order(order)
# Early return
def process_order(order: Order) -> None:
"""Обрабатывает заказ с валидацией"""
if not order:
raise ValueError("Order cannot be None")
if not order.items:
raise ValueError("Order must have items")
if not order.user:
raise ValueError("Order must have user")
if not order.user.is_active:
raise ValueError("User account is not active")
if order.total <= 0:
raise ValueError("Order total must be positive")
save_order(order)
10. Тестируемость
# Сложно тестировать - зависимости захардкодены
def send_order_confirmation(order_id: int):
order = db.query(Order).get(order_id)
user = db.query(User).get(order.user_id)
email_service.send(user.email, "Order confirmed")
# Легко тестировать - зависимости инъектируются
from typing import Protocol
class EmailService(Protocol):
def send(self, email: str, subject: str, body: str) -> None: ...
def send_order_confirmation(order: Order, user: User,
email_service: EmailService) -> None:
"""Отправляет подтверждение заказа"""
email_service.send(
user.email,
"Order Confirmation",
f"Your order #{order.id} has been confirmed"
)
Итоговый чеклист
Функция должна:
- Иметь одну ответственность
- Иметь понятное имя (что делает, не как)
- Иметь 3-4 параметра максимум
- Иметь полную типизацию
- Иметь документацию (docstring)
- Избегать побочных эффектов где возможно
- Явно обрабатывать ошибки
- Быть легко тестируемой
- Избегать магических чисел
- Использовать early return для уменьшения вложенности
Применение этих рекомендаций делает код чище, безопаснее и проще в поддержке.