0Pricing
Python Academy · Урок

TypeVar, обобщённые классы и Protocol

Определяйте повторно используемые обобщённые типы и структурную типизацию с помощью Protocol.

«TypeVar, обобщённые классы и Protocol» — бесплатный урок Python Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.

Что такое TypeVar

TypeVar объявляет переменную типа — заполнитель, которым может быть любой тип; при необходимости его можно ограничить. Переменные типа используются в обобщённых функциях и классах.

from typing import TypeVar

T = TypeVar("T")

def identity(value: T) -> T:
    return value

print(identity(42))      # int
print(identity("hello")) # str

Обобщённые функции

Функция, использующая TypeVar для типов параметров и возвращаемого значения, позволяет mypy вывести тип возвращаемого значения из типа аргумента.

from typing import TypeVar

T = TypeVar("T")

def first(items: list[T]) -> T:
    return items[0]

x: int = first([1, 2, 3])     # mypy knows x is int
s: str = first(["a","b","c"]) # mypy knows s is str

Ограниченный TypeVar

Передайте ограничения типов в TypeVar, чтобы ограничить набор допустимых типов.

from typing import TypeVar

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

def double(n: Numeric) -> Numeric:
    return n * 2

print(double(5))    # 10
print(double(2.5))  # 5.0
# double("x")  # mypy error

Обобщённые классы

Унаследуйтесь от Generic[T], чтобы создать класс, параметризованный переменной типа.

from typing import Generic, TypeVar

T = TypeVar("T")

class Stack(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []

    def push(self, item: T) -> None:
        self._items.append(item)

    def pop(self) -> T:
        return self._items.pop()

stack: Stack[int] = Stack()
stack.push(1)
print(stack.pop())   # 1

Несколько TypeVar

Используйте несколько TypeVar, чтобы параметризовать класс или функцию двумя независимыми типами.

from typing import Generic, TypeVar

K = TypeVar("K")
V = TypeVar("V")

class Pair(Generic[K, V]):
    def __init__(self, key: K, value: V) -> None:
        self.key = key
        self.value = value

p: Pair[str, int] = Pair("age", 30)
print(p.key, p.value)   # age 30

Protocol — структурная типизация

Protocol определяет интерфейс через методы и атрибуты, которыми должен обладать класс, не требуя явного наследования («утиная типизация с проверкой типов»).

from typing import Protocol

class Drawable(Protocol):
    def draw(self) -> None: ...

def render(obj: Drawable) -> None:
    obj.draw()

class Circle:
    def draw(self) -> None:
        print("Drawing circle")

render(Circle())   # works — Circle satisfies Drawable

Protocol с runtime_checkable

Добавьте @runtime_checkable к Protocol, чтобы включить проверки isinstance() во время выполнения.

from typing import Protocol, runtime_checkable

@runtime_checkable
class Closeable(Protocol):
    def close(self) -> None: ...

class File:
    def close(self) -> None: print("closed")

print(isinstance(File(), Closeable))   # True

Protocol и ABC

ABC требует явного наследования (class Dog(Animal)). Protocol работает на основе структурного соответствия: если у класса есть нужные методы, он соответствует протоколу независимо от наследования.

from typing import Protocol
from abc import ABC, abstractmethod

# ABC: nominal typing
class Printable(ABC):
    @abstractmethod
    def display(self) -> None: ...

# Protocol: structural typing
class Displayable(Protocol):
    def display(self) -> None: ...

TypeVar с bound

TypeVar("T", bound=BaseClass) ограничивает T типом BaseClass или любым его подклассом.

from typing import TypeVar

class Animal:
    def speak(self) -> str: return "..."

A = TypeVar("A", bound=Animal)

def make_speak(animal: A) -> str:
    return animal.speak()

Обобщённый псевдоним — Python 3.12

В Python 3.12 появились инструкция type для удобного создания псевдонимов типов и синтаксис class Foo[T] для обобщённых типов без импорта TypeVar.

# Python 3.12+
type Vector = list[float]
type Matrix = list[Vector]

class Stack[T]:
    def __init__(self) -> None: self._items: list[T] = []
    def push(self, item: T) -> None: self._items.append(item)
    def pop(self) -> T: return self._items.pop()

Тип Self

Self (из typing в версии 3.11+) аннотирует методы, возвращающие текущий класс; это полезно для плавных интерфейсов и подклассов.

from typing import Self

class Builder:
    def __init__(self) -> None:
        self.parts: list[str] = []

    def add(self, part: str) -> Self:
        self.parts.append(part)
        return self

b = Builder().add("a").add("b")
print(b.parts)   # ["a", "b"]

Быстрая проверка

В чём ключевое различие между Protocol и ABC в типизации Python?

Итоги

TypeVar создаёт заполнители типов для обобщённых функций и классов. Generic[T] параметризует классы. Protocol обеспечивает структурную типизацию без наследования. Используйте bound= или ограничения типов для TypeVar, чтобы ограничить допустимые типы.

Часто задаваемые вопросы

Урок «TypeVar, обобщённые классы и Protocol» бесплатный?

Да — полный текст урока «TypeVar, обобщённые классы и Protocol» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.

Чему я научусь в уроке «TypeVar, обобщённые классы и Protocol»?

Определяйте повторно используемые обобщённые типы и структурную типизацию с помощью Protocol. Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Python Academy?

Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «TypeVar, обобщённые классы и Protocol»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Python Academy?

Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы аннотаций типов
  2. Сложные типы: List, Dict, Optional, Union
  3. TypeVar, обобщённые классы и Protocol
  4. Запуск mypy и исправление ошибок типов
← Назад к Python Academy