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

Что такое аннотация?

2.0 Middle🔥 81 комментариев
#Python Core#Soft Skills

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

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

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

Аннотации (Type Hints): Типизация в Python

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

Основная концепция

# Без аннотаций — что здесь функция ожидает?
def add(a, b):
    return a + b

# add(5, 10)? add("hello", "world")? add([1], [2])?
# Непонятно!

# С аннотациями — ясно, что ожидается
def add(a: int, b: int) -> int:
    """Складывает два целых числа"""
    return a + b

# Теперь понятно: (int, int) -> int

Важно: Python игнорирует аннотации во время исполнения!

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

# Это работает (Python не проверяет типы)
add("hello", "world")  # "helloworld" — OK!
add([1], [2])  # [1, 2] — OK!

# Это работает потому, что + определен для строк и списков
# Аннотации — только документация для людей и инструментов

Типизация параметров и возвращаемых значений

# Простые типы
def greet(name: str) -> str:
    return f"Hello, {name}!"

def count_items(items: list) -> int:
    return len(items)

def is_active(flag: bool) -> bool:
    return not flag

def divide(a: float, b: float) -> float:
    return a / b

# Несколько параметров
def create_user(username: str, age: int, active: bool) -> dict:
    return {
        "username": username,
        "age": age,
        "active": active
    }

Сложные типы (typing module)

Для описания списков, словарей и т.д. нужен модуль typing:

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

# List[T] — список элементов типа T
def process_numbers(numbers: List[int]) -> int:
    return sum(numbers)

process_numbers([1, 2, 3])  # OK
process_numbers(["a", "b"])  # Аннотация скажет, что это плохо (но код выполнится)

# Dict[K, V] — словарь ключей K и значений V
def get_user_info(users: Dict[int, str]) -> str:
    return users[1]

users = {1: "Alice", 2: "Bob"}
get_user_info(users)  # OK

# Tuple — кортеж с фиксированными типами
def get_coordinates() -> Tuple[float, float]:
    return (10.5, 20.3)

x, y = get_coordinates()  # OK

# Optional[T] — может быть T или None
def find_user(user_id: int) -> Optional[Dict[str, str]]:
    if user_id == 1:
        return {"name": "Alice"}
    return None  # Может вернуть None

# Union[T1, T2, ...] — может быть одного из нескольких типов
def process_id(value: Union[int, str]) -> str:
    return str(value)

process_id(123)  # OK
process_id("abc")  # OK

# Set[T] — множество элементов типа T
def get_unique_tags(posts: List[Dict]) -> Set[str]:
    tags = set()
    for post in posts:
        tags.update(post.get('tags', []))
    return tags

Python 3.10+: Новый синтаксис

С Python 3.10+ можно использовать встроенные типы без typing:

# Python 3.10+
def process_numbers(numbers: list[int]) -> int:  # list вместо List
    return sum(numbers)

def get_user(users: dict[int, str]) -> str:  # dict вместо Dict
    return users[1]

def get_coords() -> tuple[float, float]:  # tuple вместо Tuple
    return (10.5, 20.3)

def find_user(user_id: int) -> dict[str, str] | None:  # | вместо Optional
    if user_id == 1:
        return {"name": "Alice"}
    return None

Аннотации переменных

# Аннотация переменной
name: str = "Alice"
age: int = 30
height: float = 1.75
is_active: bool = True

# Можно без значения (только аннотация)
count: int  # Значения нет, но тип задан
# count используется позже
count = 5

# Со сложными типами
users: List[Dict[str, str]] = [
    {"name": "Alice", "email": "alice@example.com"},
    {"name": "Bob", "email": "bob@example.com"}
]

config: Dict[str, Union[int, str]] = {
    "timeout": 30,
    "host": "localhost",
    "port": 8000
}

Аннотации для функций с переменным числом аргументов

from typing import *

# *args
def sum_all(*args: int) -> int:
    return sum(args)

sum_all(1, 2, 3)  # OK

# **kwargs
def create_config(**kwargs: str) -> Dict[str, str]:
    return kwargs

config = create_config(host="localhost", debug="true")

# Оба
def log_message(message: str, *args: str, **kwargs: str) -> None:
    print(f"{message}: {args} {kwargs}")

Пользовательские типы

from typing import TypeVar, Generic

# TypeVar — переменная типа (для generic функций)
T = TypeVar('T')

def get_first(items: List[T]) -> T:
    """Возвращает первый элемент списка (сохраняя тип)"""
    return items[0]

first_int = get_first([1, 2, 3])  # Тип первого значения: int
first_str = get_first(["a", "b"])  # Тип первого значения: str

# Generic класс
K = TypeVar('K')
V = TypeVar('V')

class Cache(Generic[K, V]):
    def __init__(self):
        self._data: Dict[K, V] = {}
    
    def get(self, key: K) -> Optional[V]:
        return self._data.get(key)
    
    def set(self, key: K, value: V) -> None:
        self._data[key] = value

# Использование
cache_int_str: Cache[int, str] = Cache()
cache_int_str.set(1, "hello")
value = cache_int_str.get(1)  # Тип: Optional[str]

Практические примеры

Пример 1: Функция обработки данных

from typing import List, Dict, Optional

def filter_users(
    users: List[Dict[str, any]],
    active_only: bool = True
) -> List[Dict[str, any]]:
    """Фильтрует пользователей по активности"""
    if active_only:
        return [u for u in users if u.get('active', False)]
    return users

users_data = [
    {"name": "Alice", "active": True},
    {"name": "Bob", "active": False}
]

active = filter_users(users_data)  # OK

Пример 2: Класс с типизацией

from typing import Optional, List
from datetime import datetime

class User:
    def __init__(self, name: str, age: int, email: Optional[str] = None):
        self.name: str = name
        self.age: int = age
        self.email: Optional[str] = email
        self.created_at: datetime = datetime.now()
    
    def get_info(self) -> Dict[str, any]:
        return {
            "name": self.name,
            "age": self.age,
            "email": self.email
        }
    
    @staticmethod
    def create_admin(name: str) -> 'User':
        return User(name, age=0, email="admin@example.com")

user = User("Alice", 30, "alice@example.com")
info = user.get_info()  # Dict[str, any]

Пример 3: Callback функции

from typing import Callable, List

def apply_to_all(
    items: List[int],
    processor: Callable[[int], int]  # Функция (int) -> int
) -> List[int]:
    """Применяет функцию к каждому элементу"""
    return [processor(item) for item in items]

# Использование
def double(x: int) -> int:
    return x * 2

result = apply_to_all([1, 2, 3], double)  # [2, 4, 6]

Проверка типов: mypy

Аннотации полезны, но их проверяет mypy — статический анализатор:

# Установка
pip install mypy

# Проверка файла
mypy my_code.py

# Проверка проекта
mypy .

Пример ошибки, которую найдет mypy:

# code.py
def add(a: int, b: int) -> int:
    return a + b

result = add("hello", "world")  # ERROR!

# mypy output:
# error: Argument 1 to "add" has incompatible type "str"; expected "int"
# error: Argument 2 to "add" has incompatible type "str"; expected "int"

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

# 1. Аннотируй все публичные функции
# Хорошо
def calculate(x: int) -> int:
    return x * 2

# 2. Используй Optional для nullable значений
# Хорошо
def find_user(user_id: int) -> Optional[User]:
    ...

# Плохо (неясно, может ли быть None)
def find_user(user_id: int) -> User:
    ...

# 3. Не переусложняй
# Хорошо
def process(data: Dict[str, int]) -> List[int]:
    ...

# Плохо (слишком сложно)
from typing import Callable, Awaitable, TypeVar, Union, overload
# (редко нужно)

# 4. Используй type: ignore редко
# Плохо
result = some_untyped_library.func()  # type: ignore

# Лучше
from typing import Any
result: Any = some_untyped_library.func()

Резюме

Аннотация — это указание типа для переменной, параметра или возвращаемого значения. Это не влияет на исполнение кода, но помогает:

  • Документировать ожидаемые типы
  • Найти ошибки с помощью mypy
  • Улучшить автодополнение в IDE
  • Сделать код понятнее

Аннотации критичны в production Python коде и являются лучшей практикой.

Что такое аннотация? | PrepBro