<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Аннотации типов в Python — полный гайд с примерами]]></title><description><![CDATA[<p dir="auto">Python динамически типизирован: интерпретатор не проверяет типы во время выполнения. Аннотации типов — это <strong>подсказки</strong> (type hints) для инструментов статического анализа, IDE и разработчиков.</p>
<p dir="auto">Три главных эффекта:</p>
<ul>
<li><strong>Читаемость</strong> — сразу видно, что принимает и возвращает функция</li>
<li><strong>Статический анализ</strong> — mypy, pyright находят ошибки до запуска</li>
<li><strong>Автодополнение в IDE</strong> — Zed, VS Code, PyCharm знают типы и предлагают правильные методы</li>
</ul>
<blockquote>
<p dir="auto">Аннотации не влияют на скорость выполнения и не бросают исключений сами по себе. Проверку можно включить явно через runtime-библиотеки.</p>
</blockquote>
<hr />
<h2>Базовый синтаксис</h2>
<h3>Переменные</h3>
<pre><code class="language-python">name: str = "Alice"
age: int = 30
pi: float = 3.14
is_active: bool = True
nothing: None = None

# Объявление без инициализации (для классов, модульного уровня)
user_id: int  # значения ещё нет, но тип зафиксирован
</code></pre>
<h3>Функции</h3>
<pre><code class="language-python">def greet(name: str) -&gt; str:
    return f"Hello, {name}"

def add(a: int, b: int) -&gt; int:
    return a + b

def log(message: str) -&gt; None:  # ничего не возвращает
    print(message)
</code></pre>
<p dir="auto">Синтаксис: после имени параметра ставится <code>: тип</code>, после скобок <code>-&gt; тип</code> для возвращаемого значения.</p>
<hr />
<h2>Встроенные коллекции (Python 3.9+)</h2>
<p dir="auto">С Python 3.9 можно использовать встроенные типы напрямую, без импорта из <code>typing</code>:</p>
<pre><code class="language-python">def process(items: list[int]) -&gt; dict[str, int]:
    return {str(i): i for i in items}

def lookup(mapping: dict[str, list[float]]) -&gt; tuple[str, ...]:
    return tuple(mapping.keys())

coords: set[int] = {1, 2, 3}
pair: tuple[int, str] = (42, "hello")
</code></pre>
<p dir="auto">До Python 3.9 нужно было писать <code>List[int]</code>, <code>Dict[str, int]</code> из модуля <code>typing</code>.</p>
<hr />
<h2>Модуль <code>typing</code> — специальные конструкции</h2>
<h3><code>Optional</code> — значение или <code>None</code></h3>
<pre><code class="language-python">from typing import Optional

def find_user(user_id: int) -&gt; Optional[str]:
    if user_id == 1:
        return "Alice"
    return None
</code></pre>
<p dir="auto">С Python 3.10 то же самое можно записать через <code>|</code>:</p>
<pre><code class="language-python">def find_user(user_id: int) -&gt; str | None:  # Python 3.10+
    ...
</code></pre>
<h3><code>Union</code> — один из нескольких типов</h3>
<pre><code class="language-python">from typing import Union

def stringify(value: Union[int, float, str]) -&gt; str:
    return str(value)

# Python 3.10+
def stringify(value: int | float | str) -&gt; str:
    return str(value)
</code></pre>
<h3><code>Any</code> — отключение проверки</h3>
<pre><code class="language-python">from typing import Any

def debug(value: Any) -&gt; None:
    print(value)
</code></pre>
<p dir="auto"><code>Any</code> совместим с любым типом в обе стороны. Используется, когда тип действительно неизвестен или для постепенной миграции.</p>
<h3><code>Literal</code> — конкретные допустимые значения</h3>
<pre><code class="language-python">from typing import Literal

def set_direction(direction: Literal["left", "right", "up", "down"]) -&gt; None:
    ...

def get_status() -&gt; Literal[0, 1, -1]:
    return 0
</code></pre>
<h3><code>Final</code> — константы</h3>
<pre><code class="language-python">from typing import Final

MAX_SIZE: Final = 100
API_URL: Final[str] = "https://api.example.com"
</code></pre>
<p dir="auto">Переменная, помеченная <code>Final</code>, не должна переопределяться.</p>
<hr />
<h2>Callable и функции как аргументы</h2>
<pre><code class="language-python">from typing import Callable

# Функция принимает int, возвращает str
def apply(func: Callable[[int], str], value: int) -&gt; str:
    return func(value)

# Функция без аргументов, возвращающая None
Handler = Callable[[], None]

def register(callback: Handler) -&gt; None:
    callback()
</code></pre>
<hr />
<h2>TypeVar — обобщённые функции</h2>
<p dir="auto"><code>TypeVar</code> нужен, когда тип возврата зависит от типа аргумента:</p>
<pre><code class="language-python">from typing import TypeVar

T = TypeVar("T")

def first(items: list[T]) -&gt; T:
    return items[^0]

result_int: int = first([1, 2, 3])      # T = int
result_str: str = first(["a", "b"])     # T = str
</code></pre>
<p dir="auto"><code>TypeVar</code> с ограничениями:</p>
<pre><code class="language-python">from typing import TypeVar

Number = TypeVar("Number", int, float)

def double(x: Number) -&gt; Number:
    return x * 2
</code></pre>
<h3>Python 3.12 — новый синтаксис дженериков</h3>
<pre><code class="language-python"># Python 3.12+, не нужно объявлять TypeVar явно
def first[T](items: list[T]) -&gt; T:
    return items[^0]

def zip_with[T, U](a: list[T], b: list[U]) -&gt; list[tuple[T, U]]:
    return list(zip(a, b))
</code></pre>
<hr />
<h2>Аннотации в классах</h2>
<pre><code class="language-python">class User:
    name: str
    age: int
    email: str | None = None  # поле со значением по умолчанию

    def __init__(self, name: str, age: int) -&gt; None:
        self.name = name
        self.age = age

    def greet(self) -&gt; str:
        return f"Hi, I'm {self.name}"
</code></pre>
<h3><code>ClassVar</code> — атрибуты класса, не экземпляра</h3>
<pre><code class="language-python">from typing import ClassVar

class Config:
    debug: ClassVar[bool] = False
    max_retries: ClassVar[int] = 3
    timeout: float = 30.0  # атрибут экземпляра
</code></pre>
<hr />
<h2>TypedDict — словари с фиксированной структурой</h2>
<pre><code class="language-python">from typing import TypedDict

class Movie(TypedDict):
    title: str
    year: int
    rating: float

def print_movie(movie: Movie) -&gt; None:
    print(f"{movie['title']} ({movie['year']})")

film: Movie = {"title": "Inception", "year": 2010, "rating": 8.8}
</code></pre>
<p dir="auto">С необязательными ключами:</p>
<pre><code class="language-python">from typing import TypedDict, NotRequired

class Config(TypedDict):
    host: str
    port: int
    debug: NotRequired[bool]  # Python 3.11+
</code></pre>
<hr />
<h2>Protocol — структурная типизация (duck typing)</h2>
<p dir="auto"><code>Protocol</code> позволяет описать интерфейс, которому объект должен соответствовать, без наследования:</p>
<pre><code class="language-python">from typing import Protocol

class Drawable(Protocol):
    def draw(self) -&gt; None: ...

class Circle:
    def draw(self) -&gt; None:
        print("Drawing circle")

class Square:
    def draw(self) -&gt; None:
        print("Drawing square")

def render(shape: Drawable) -&gt; None:
    shape.draw()

render(Circle())  # OK, хотя Circle не наследует Drawable
render(Square())  # OK
</code></pre>
<hr />
<h2><code>dataclass</code> + аннотации</h2>
<pre><code class="language-python">from dataclasses import dataclass, field

@dataclass
class Point:
    x: float
    y: float
    label: str = "default"
    tags: list[str] = field(default_factory=list)

p = Point(1.0, 2.5)
</code></pre>
<p dir="auto"><code>@dataclass</code> читает аннотации классовых полей и автоматически генерирует <code>__init__</code>, <code>__repr__</code>, <code>__eq__</code>.</p>
<hr />
<h2><code>overload</code> — перегрузка сигнатур</h2>
<pre><code class="language-python">from typing import overload

@overload
def process(value: int) -&gt; str: ...
@overload
def process(value: str) -&gt; int: ...

def process(value: int | str) -&gt; str | int:
    if isinstance(value, int):
        return str(value)
    return len(value)
</code></pre>
<p dir="auto"><code>@overload</code> позволяет статическому анализатору понять, какой тип вернётся при каком входе.</p>
<hr />
<h2><code>TYPE_CHECKING</code> — избегаем циклических импортов</h2>
<pre><code class="language-python">from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from mymodule import HeavyClass  # импортируется только при статическом анализе

def process(obj: "HeavyClass") -&gt; None:
    ...
</code></pre>
<p dir="auto"><code>from __future__ import annotations</code> (PEP 563) делает все аннотации строками-ленивыми вычислениями, что полностью решает проблему forward references.</p>
<hr />
<h2><code>ParamSpec</code> и <code>Concatenate</code> — аннотации для декораторов</h2>
<pre><code class="language-python">from typing import ParamSpec, TypeVar, Callable
import functools

P = ParamSpec("P")
R = TypeVar("R")

def logged(func: Callable[P, R]) -&gt; Callable[P, R]:
    @functools.wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -&gt; R:
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@logged
def add(a: int, b: int) -&gt; int:
    return a + b
</code></pre>
<p dir="auto"><code>ParamSpec</code> сохраняет полную сигнатуру оборачиваемой функции — IDE будет знать типы аргументов декорированной функции.</p>
<hr />
<h2><code>Self</code> — тип текущего класса</h2>
<pre><code class="language-python">from typing import Self  # Python 3.11+

class Builder:
    def set_name(self, name: str) -&gt; Self:
        self.name = name
        return self

    def set_age(self, age: int) -&gt; Self:
        self.age = age
        return self

b = Builder().set_name("Alice").set_age(30)
</code></pre>
<p dir="auto">Используйте <code>Self</code> вместо имени класса в строке, чтобы наследники получали правильный тип при цепочечных вызовах.</p>
<hr />
<h2><code>Never</code> и <code>NoReturn</code></h2>
<pre><code class="language-python">from typing import NoReturn, Never  # Never появился в 3.11

def crash() -&gt; NoReturn:
    raise RuntimeError("Fatal error")

def assert_never(value: Never) -&gt; Never:
    raise AssertionError(f"Unexpected value: {value}")
</code></pre>
<p dir="auto"><code>NoReturn</code> говорит: функция никогда не возвращает управление (бросает исключение или бесконечный цикл). <code>Never</code> — тип-дно, с которым ничего не совместимо.</p>
<hr />
<h2>Инструменты статического анализа</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th style="text-align:left">Инструмент</th>
<th style="text-align:left">Установка</th>
<th style="text-align:left">Запуск</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>mypy</strong></td>
<td style="text-align:left"><code>uv add mypy</code></td>
<td style="text-align:left"><code>mypy src/</code></td>
</tr>
<tr>
<td style="text-align:left"><strong>pyright</strong></td>
<td style="text-align:left"><code>uv add pyright</code></td>
<td style="text-align:left"><code>pyright</code></td>
</tr>
<tr>
<td style="text-align:left"><strong>ruff</strong></td>
<td style="text-align:left"><code>uv add ruff</code></td>
<td style="text-align:left"><code>ruff check .</code> (lint + types)</td>
</tr>
</tbody>
</table>
<p dir="auto">Пример конфига <code>mypy.ini</code>:</p>
<pre><code class="language-ini">[mypy]
python_version = 3.14
strict = true
ignore_missing_imports = true
</code></pre>
<p dir="auto">Флаг <code>--strict</code> включает полный набор проверок, включая <code>disallow_untyped_defs</code>, <code>warn_return_any</code> и другие.</p>
<hr />
<h2>Быстрая шпаргалка по версиям</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th style="text-align:left">Конструкция</th>
<th style="text-align:left">Минимальная версия</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>list[int]</code>, <code>dict[str, int]</code> напрямую</td>
<td style="text-align:left">3.9</td>
</tr>
<tr>
<td style="text-align:left"><code>X \| Y</code> вместо <code>Union[X, Y]</code></td>
<td style="text-align:left">3.10</td>
</tr>
<tr>
<td style="text-align:left"><code>Self</code>, <code>Never</code>, <code>NotRequired</code></td>
<td style="text-align:left">3.11</td>
</tr>
<tr>
<td style="text-align:left"><code>def f[T](...)</code> — новый синтаксис дженериков</td>
<td style="text-align:left">3.12</td>
</tr>
</tbody>
</table>
<hr />
<h2>Полезные источники</h2>
<ul>
<li><strong>PEP 484</strong> — основной PEP, вводящий аннотации типов: <a href="http://python.org/dev/peps/pep-0484" target="_blank" rel="noopener noreferrer">python.org/dev/peps/pep-0484</a></li>
<li><strong>PEP 526</strong> — аннотации переменных: <a href="http://python.org/dev/peps/pep-0526" target="_blank" rel="noopener noreferrer">python.org/dev/peps/pep-0526</a></li>
<li><strong>PEP 604</strong> — синтаксис <code>X | Y</code>: <a href="http://python.org/dev/peps/pep-0604" target="_blank" rel="noopener noreferrer">python.org/dev/peps/pep-0604</a></li>
<li><strong>PEP 695</strong> — дженерики через <code>[T]</code> в Python 3.12: <a href="http://python.org/dev/peps/pep-0695" target="_blank" rel="noopener noreferrer">python.org/dev/peps/pep-0695</a></li>
<li><strong>Документация mypy</strong>: <a href="http://mypy.readthedocs.io" target="_blank" rel="noopener noreferrer">mypy.readthedocs.io</a></li>
<li><strong>typing — официальная документация</strong>: <a href="http://docs.python.org/3/library/typing.html" target="_blank" rel="noopener noreferrer">docs.python.org/3/library/typing.html</a></li>
<li><strong>Pyright</strong>: <a href="http://github.com/microsoft/pyright" target="_blank" rel="noopener noreferrer">github.com/microsoft/pyright</a><br />
<span style="display:none"><a href="https://pymupdf.readthedocs.io/en/latest/page.html" target="_blank" rel="noopener noreferrer">^10</a><a href="https://pymupdf.readthedocs.io/en/latest/document.html?highlight=Document" target="_blank" rel="noopener noreferrer">^12</a><a href="https://pymupdf.readthedocs.io/en/latest/changes.html?spm=a2c6h.13046898.publish-article.9.7d9a6ffa2QjJUp" target="_blank" rel="noopener noreferrer">^14</a><a href="https://pymupdf.readthedocs.io/en/latest/document.html" target="_blank" rel="noopener noreferrer">^16</a><a href="https://pymupdf.readthedocs.io/en/latest/changes.html" target="_blank" rel="noopener noreferrer">^18</a><a href="https://pymupdf.readthedocs.io/ja/latest/page.html" target="_blank" rel="noopener noreferrer">^20</a><a href="https://pymupdf.readthedocs.io/en/latest/annot.html" target="_blank" rel="noopener noreferrer">^6</a><a href="https://pymupdf.readthedocs.io/en/1.23.6/page.html" target="_blank" rel="noopener noreferrer">^8</a></span></li>
</ul>
<div>⁂</div>
]]></description><link>https://forum.exlends.com/topic/2219/annotacii-tipov-v-python-polnyj-gajd-s-primerami</link><generator>RSS for Node</generator><lastBuildDate>Sat, 02 May 2026 13:15:15 GMT</lastBuildDate><atom:link href="https://forum.exlends.com/topic/2219.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 30 Apr 2026 13:33:32 GMT</pubDate><ttl>60</ttl></channel></rss>