← Назад к вопросам

Когда нужно использовать параметр функции?

1.0 Junior🔥 191 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда использовать параметры функции

Параметры функции — это способ сделать функцию гибкой, переиспользуемой и тестируемой. Правильное использование параметров критично для качественного кода.

Основной принцип

Используй параметр ВСЕГДА когда значение может быть разным для разных вызовов функции. Не хардкодь значения — делай их параметрами.

1. Обязательные параметры

Используй когда значение всегда нужно для работы функции:

# Правильно — параметр обязателен
def calculate_discount(price: float, discount_percent: float) -> float:
    return price * (1 - discount_percent / 100)

calculate_discount(100, 10)  # 90.0

# Неправильно — хардкод
def calculate_discount_bad(price: float) -> float:
    discount_percent = 10  # Нельзя менять!
    return price * (1 - discount_percent / 100)

2. Опциональные параметры

Используй когда значение может быть не обязательным или есть разумное значение по умолчанию:

# Правильно — значение по умолчанию
def fetch_users(limit: int = 10, offset: int = 0, active: bool = True):
    pass

fetch_users()  # Использует дефолты
fetch_users(limit=50)  # Переопределяет только limit
fetch_users(limit=50, offset=100, active=False)

3. *args (Variadic positional arguments)

Используй когда количество параметров не известно заранее:

# Правильно — неограниченное количество значений
def sum_numbers(*numbers: float) -> float:
    return sum(numbers)

sum_numbers(1, 2, 3)  # 6
sum_numbers(1, 2, 3, 4, 5)  # 15

# Правильно — список или кортеж
def print_all(*messages: str):
    for msg in messages:
        print(msg)

print_all("Hello", "World", "Python")

4. **kwargs (Variadic keyword arguments)

Используй когда атрибуты объекта динамичны или много опциональных параметров:

# Правильно — конфигурация с динамичными ключами
def create_database(host: str, port: int, **options):
    config = {"host": host, "port": port, **options}
    return Database(config)

db = create_database(
    host="localhost",
    port=5432,
    user="admin",
    password="secret",
    ssl=True
)

# Правильно — конструкторы компонентов
def Button(**props):
    return f"<button {' '.join(f'{k}={v}' for k, v in props.items())}>"

5. Позиционные и именованные параметры

# Python 3.8+ — можем разделить позиционные и именованные

# / означает все до этого только позиционные
def divide(a: float, b: float, /) -> float:
    return a / b

divide(10, 2)  # OK

# * означает все после этого только именованные
def create_user(name: str, *, role: str = "user", active: bool = True):
    pass

create_user("John", role="admin")  # OK

# Комбинирование
def request(method: str, url: str, /, *, headers: dict = None, **kwargs):
    pass

6. Типизация параметров

from typing import Optional, Union, Callable

# Явная типизация — всегда лучше
def process(data: list[str]) -> dict[str, int]:
    return {item: len(item) for item in data}

# Union — несколько типов
def convert(value: int | str) -> str:
    return str(value)

# Optional — может быть None
def fetch(user_id: int, default: Optional[str] = None) -> str:
    return default or "Anonymous"

# Callable — функция как параметр
def apply_function(data: list[int], func: Callable[[int], int]) -> list[int]:
    return [func(x) for x in data]

apply_function([1, 2, 3], lambda x: x * 2)  # [2, 4, 6]

7. Параметры с валидацией

from dataclasses import dataclass

@dataclass
class CreateUserRequest:
    username: str
    email: str
    age: int
    
    def __post_init__(self):
        if len(self.username) < 3:
            raise ValueError("Username too short")
        if self.age < 18:
            raise ValueError("Must be 18+")

def create_user(request: CreateUserRequest) -> dict:
    return {"username": request.username, "email": request.email}

request = CreateUserRequest("john", "john@example.com", 25)
user = create_user(request)

8. Dependency Injection через параметры

def send_notification(
    user_id: int,
    message: str,
    sender: Callable[[str, str], None] = None
):
    if sender is None:
        sender = default_email_sender
    
    sender(user_id, message)

# Использование в коде
send_notification(123, "Hello")

# Использование в тестах
test_messages = []
def test_sender(user_id, message):
    test_messages.append((user_id, message))

send_notification(123, "Hello", sender=test_sender)
assert (123, "Hello") in test_messages

Ключевые правила

  1. Все ли переменные должны быть параметрами? Хардкода быть не должно
  2. Есть ли разумные значения по умолчанию? Добавить дефолты
  3. Параметры типизированы? Явная типизация всегда
  4. Слишком ли много параметров? (больше 5) Объединить в объект
  5. Порядок параметров логичен? Обязательные затем опциональные

Итого

Параметры делают функцию:

  • Гибкой — работает с разными данными
  • Переиспользуемой — не привязана к конкретным значениям
  • Тестируемой — можно передать mock-объекты
  • Понятной — явно видно какие данные нужны
Когда нужно использовать параметр функции? | PrepBro