Что такое type checking?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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, особенно в больших проектах.