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

Что такое type checking?

3.0 Senior🔥 111 комментариев
#DevOps и инфраструктура#Django

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

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

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

Type Checking в Python

Type checking — это процесс проверки типов данных переменных, аргументов функций и возвращаемых значений для предотвращения ошибок типа. В Python это может быть выполнено как статически (во время разработки) через инструменты вроде mypy, так и динамически (во время выполнения) через встроенные механизмы.

Статический Type Checking с Type Hints

Type hints (Аннотации типов) — это встроенная в Python функция для указания ожидаемых типов:

# Без type hints — неясно, какие типы ожидаются
def add(a, b):
    return a + b

add(5, 3)        # OK: 8
add("5", "3")    # OK: "53"
add(5, "3")      # OK: "53" — неожиданное поведение!

С type hints:

def add(a: int, b: int) -> int:
    return a + b

add(5, 3)        # OK
add("5", "3")    # Type checker выдаст ошибку
add(5, "3")      # Type checker выдаст ошибку

Базовые Type Hints

from typing import List, Dict, Optional, Union, Tuple

# Простые типы
name: str = "Alice"
age: int = 30
height: float = 1.75
active: bool = True

# Коллекции
users: List[str] = ["Alice", "Bob"]
scores: Dict[str, int] = {"Alice": 100, "Bob": 95}
coords: Tuple[int, int] = (10, 20)

# Optional — может быть значение или None
emails: Optional[List[str]] = ["alice@example.com"]
emails_none: Optional[List[str]] = None

# Union — один из нескольких типов
value: Union[int, str] = 42  # или "42"

Type Hints для функций

from typing import List, Dict, Optional

def process_users(users: List[Dict[str, str]]) -> Dict[str, int]:
    """
    Обрабатывает список пользователей и возвращает словарь с результатами.
    
    Args:
        users: Список словарей с информацией о пользователях
    
    Returns:
        Словарь с количеством пользователей по группам
    """
    result = {}
    for user in users:
        group = user.get("group", "unknown")
        result[group] = result.get(group, 0) + 1
    return result

# Использование
data = [{"name": "Alice", "group": "admin"}, {"name": "Bob", "group": "user"}]
stats = process_users(data)
print(stats)  # {'admin': 1, 'user': 1}

Статический Type Checker: mypy

mypy — это утилита для проверки типов перед выполнением кода:

pip install mypy
mypy script.py

Пример файла для проверки:

# script.py
def greet(name: str) -> str:
    return f"Hello, {name}!"

result = greet("Alice")  # OK
result = greet(42)       # Error: Argument 1 to "greet" has incompatible type "int"; expected "str"

Запуск mypy:

$ mypy script.py
script.py:5: error: Argument 1 to "greet" has incompatible type "int"; expected "str"
Found 1 error in 1 file (checked 1 source file)

Динамический Type Checking во время выполнения

isinstance() — проверка типа во время выполнения:

def process_data(data):
    if isinstance(data, list):
        return sum(data)
    elif isinstance(data, str):
        return len(data)
    else:
        raise TypeError(f"Unsupported type: {type(data)}")

print(process_data([1, 2, 3]))      # 6
print(process_data("hello"))        # 5
print(process_data(42))             # TypeError

Декоратор для проверки типов:

from functools import wraps
from typing import get_type_hints

def validate_types(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        hints = get_type_hints(func)
        arg_names = func.__code__.co_varnames[:len(args)]
        
        for arg_name, arg_value in zip(arg_names, args):
            if arg_name in hints:
                expected_type = hints[arg_name]
                if not isinstance(arg_value, expected_type):
                    raise TypeError(
                        f"Argument {arg_name} must be {expected_type}, "
                        f"got {type(arg_value)}"
                    )
        return func(*args, **kwargs)
    return wrapper

@validate_types
def add(a: int, b: int) -> int:
    return a + b

print(add(5, 3))        # 8
print(add("5", 3))      # TypeError: Argument a must be <class 'int'>, got <class 'str'>

Продвинутые Type Hints

Generic типы:

from typing import Generic, TypeVar

T = TypeVar('T')  # Переменный тип

class Stack(Generic[T]):
    def __init__(self):
        self.items: List[T] = []
    
    def push(self, item: T) -> None:
        self.items.append(item)
    
    def pop(self) -> T:
        return self.items.pop()

# Использование с конкретными типами
int_stack: Stack[int] = Stack()
int_stack.push(10)
int_stack.push(20)
value: int = int_stack.pop()  # mypy знает, что это int

str_stack: Stack[str] = Stack()
str_stack.push("hello")
str_stack.push("world")
word: str = str_stack.pop()  # mypy знает, что это str

Callable типы:

from typing import Callable

def apply_function(
    values: List[int],
    func: Callable[[int], int]
) -> List[int]:
    return [func(x) for x in values]

result = apply_function([1, 2, 3], lambda x: x ** 2)
print(result)  # [1, 4, 9]

Type Checking в Production

Включение mypy в CI/CD pipeline:

# Makefile или GitHub Actions
mypy src/ --strict
if [ $? -ne 0 ]; then
    echo "Type checking failed"
    exit 1
fi

Конфигурация mypy (mypy.ini):

[mypy]
python_version = 3.10
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True  # Запретить функции без типов

Плюсы и минусы Type Checking

Плюсы:

  • Ловит ошибки типов на ранней стадии
  • Улучшает документацию кода
  • Помогает IDE с автодополнением
  • Упрощает рефакторинг
  • Лучше для командной разработки

Минусы:

  • Требует дополнительного времени на написание
  • Некоторые динамические паттерны сложны для типирования
  • Не гарантирует отсутствие ошибок в runtime

Лучшие практики

# 1. Типируйте функции, особенно public API
def fetch_user(user_id: int) -> Optional[Dict[str, str]]:
    pass

# 2. Используйте Optional вместо None как default
def process(data: Optional[List[int]] = None) -> int:
    if data is None:
        data = []
    return sum(data)

# 3. Типируйте сложные структуры
from typing import TypedDict

class User(TypedDict):
    id: int
    name: str
    email: str

def create_user(user: User) -> bool:
    pass

Type checking — это мощный инструмент для написания надёжного, поддерживаемого и самодокументирующегося кода на Python, особенно в больших проектах.