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

Где могут применяться аннотации в Python?

1.3 Junior🔥 181 комментариев
#Python Core

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

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

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

Аннотации (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()

Вывод

Аннотации применяются для:

  1. IDE поддержки — автодополнение, проверка ошибок
  2. Type checking — mypy, pyright находят ошибки
  3. Документации — читатели сразу видят какие типы нужны
  4. Фреймворков — FastAPI, Pydantic используют аннотации для валидации
  5. Рефакторинга — IDE может безопасно переименовывать переменные
  6. Production кода — обязательны в команде для избежания багов

В 2025 году type hints — это стандарт в Python разработке, особенно в production коде.