Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Аннотации (Type Hints) в Python
Аннотации — это способ указать ожидаемые типы переменных, параметров и возвращаемых значений. Они не изменяют поведение кода (Python остаётся динамически типизированным), но помогают инструментам и разработчикам лучше понимать код.
1. Аннотации функций
Самое распространённое применение — указание типов параметров и возвращаемого значения:
# Без аннотаций — непонятно какие типы ожидаются
def calculate(a, b, operation):
if operation == 'add':
return a + b
elif operation == 'multiply':
return a * b
# С аннотациями — ясно что нужно передать
def calculate(a: int, b: int, operation: str) -> int:
if operation == 'add':
return a + b
elif operation == 'multiply':
return a * b
# Использование
result: int = calculate(5, 3, 'add') # Ясно что вернется int
2. Аннотации переменных
Указание типов для локальных переменных и атрибутов:
class User:
name: str
age: int
email: str
is_active: bool = True
def __init__(self, name: str, age: int, email: str):
self.name = name
self.age = age
self.email = email
user: User = User('Alice', 30, 'alice@example.com')
counter: int = 0
items: list[str] = ['a', 'b', 'c']
3. Сложные типы
Optional — значение может быть None:
from typing import Optional
def get_user_by_id(user_id: int) -> Optional[dict]:
# Может вернуть словарь или None
if user_id > 0:
return {'id': user_id, 'name': 'Alice'}
return None
Union — несколько возможных типов:
from typing import Union
def process(value: Union[int, str]) -> str:
# Может принять int или str
return str(value).upper()
List, Dict, Tuple — типизированные коллекции:
from typing import List, Dict, Tuple
def get_users() -> List[Dict[str, Union[int, str]]]:
return [
{'id': 1, 'name': 'Alice'},
{'id': 2, 'name': 'Bob'}
]
coordinates: Tuple[float, float, float] = (1.0, 2.0, 3.0)
scores: Dict[str, int] = {'Alice': 100, 'Bob': 95}
Callable — функции как параметры:
from typing import Callable
def apply_operation(a: int, b: int, operation: Callable[[int, int], int]) -> int:
# operation принимает два int и возвращает int
return operation(a, b)
add = lambda x, y: x + y
result = apply_operation(5, 3, add)
4. Аннотации в классах
Наследование и типы:
from typing import Protocol
class Animal(Protocol):
def speak(self) -> str: ...
class Dog:
def speak(self) -> str:
return "Woof!"
class Cat:
def speak(self) -> str:
return "Meow!"
def make_sound(animal: Animal) -> None:
print(animal.speak())
make_sound(Dog()) # OK
make_sound(Cat()) # OK
Generics — обобщённые типы:
from typing import TypeVar, Generic
T = TypeVar('T')
class Container(Generic[T]):
def __init__(self, value: T):
self.value = value
def get(self) -> T:
return self.value
container_int: Container[int] = Container(42)
container_str: Container[str] = Container('hello')
5. Практическое применение
Type checking с mypy:
# main.py
def greet(name: str) -> str:
return f"Hello, {name}!"
result: str = greet("Alice") # OK
result = greet(123) # Ошибка: mypy обнаружит
Запуск mypy:
mypy main.py
# error: Argument 1 to "greet" has incompatible type "int"; expected "str"
IDE автодополнение:
user: dict[str, int] = {'id': 1}
# IDE знает что user это dict
user['name'] = 'Alice' # IDE может предупредить что key не существует в типе
name: str = user['id'] # IDE предупредит: int != str
Валидация с Pydantic:
from pydantic import BaseModel, field_validator
class User(BaseModel):
id: int
name: str
age: int
@field_validator('age')
@classmethod
def age_must_be_positive(cls, v):
if v < 0:
raise ValueError('Age cannot be negative')
return v
user = User(id=1, name='Alice', age=30) # OK
user = User(id=1, name='Alice', age=-5) # ValidationError
6. Аннотации в современном Python 3.10+
Union вместо | (PEP 604):
# До Python 3.10
from typing import Union
def process(value: Union[int, str]) -> None: pass
# Python 3.10+
def process(value: int | str) -> None: pass
Match statement с типизацией:
def handle_value(value: int | str | list) -> str:
match value:
case int():
return f"Integer: {value}"
case str():
return f"String: {value}"
case list():
return f"List with {len(value)} items"
case _:
return "Unknown"
7. Инструменты для работы с аннотациями
Рефакторинг с аннотациями:
# pyright — тип-чекинг от Microsoft
pyright script.py
# mypy — классический type checker
mypy script.py
# pydantic — валидация данных
from pydantic import BaseModel
# dataclass — структурированные данные
from dataclasses import dataclass
8. Лучшие практики
Используй аннотации везде:
# Плохо: без аннотаций
def process(data):
return len(data)
# Хорошо: с аннотациями
def process(data: list[str]) -> int:
return len(data)
Избегай any если возможно:
# Плохо
def handle(x: any) -> any:
return x
# Хорошо
T = TypeVar('T')
def handle(x: T) -> T:
return x
Используй Protocol для duck typing:
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing circle")
def render(shape: Drawable) -> None:
shape.draw()
Вывод
Аннотации применяются для:
- IDE поддержки — автодополнение, проверка ошибок
- Type checking — mypy, pyright находят ошибки
- Документации — читатели сразу видят какие типы нужны
- Фреймворков — FastAPI, Pydantic используют аннотации для валидации
- Рефакторинга — IDE может безопасно переименовывать переменные
- Production кода — обязательны в команде для избежания багов
В 2025 году type hints — это стандарт в Python разработке, особенно в production коде.