Сообщить об ошибке.

Функции и декораторы модуля typing в Python

В разделе представлены функции и декораторы модуля typing, представляющие дополнительные возможности по аннотированию исходного кода.

Содержание:


Функции модуля модуля typing.

typing.cast(typ, val):

Функция typing.cast() приводит значение val к типу typ.

Функция возвращает значение без изменений. Для средства проверки типов это означает, что возвращаемое значение имеет обозначенный тип, но во время выполнения намеренно ничего не проверяется, чтобы старт программы был как можно быстрее.

typing.assert_type(val, typ, /):

Новое в Python 3.11.

Функция typing.assert_type() (добавлена в Python 3.11.) просит средство проверки статического типа подтвердить, что val имеет предполагаемый тип typ.

Когда средство проверки типов встречает вызов typing.assert_type(), оно выдает ошибку, если значение не относится к указанному типу:

def greet(name: str) -> None:
    # ОК, предположительный тип `name` - `str`
    assert_type(name, str)  
    # ошибка проверки типа
    assert_type(name, int)

Во время выполнения программы этот вызов возвращает первый аргумент без изменений и без побочных эффектов.

Эта функция полезна для того, чтобы гарантировать, что понимание скрипта программой проверки типов соответствует намерениям разработчика:

def complex_function(arg: object):
    # Допустим здесь выполняется некоторая сложная логика по сужению 
    # типа, в результате чего итоговый тип должен быть `int`
    ...
    # здесь проверяется, правильно ли средство 
    # проверки типов понимает написанную функцию
    assert_type(arg, int)

typing.assert_never(arg, /):

Новое в Python 3.11.

Функция typing.assert_never() (добавлена в Python 3.11.) просит средство проверки статического типа подтвердить, что строка кода недоступна.

Пример:

def int_or_str(arg: int | str) -> None:
    match arg:
        case int():
            print("It's an int")
        case str():
            print("It's a str")
        case _ as unreachable:
            assert_never(unreachable)

Здесь аннотации позволяют средству проверки типов сделать вывод, что последний случай в case никогда не может быть выполнен, потому что arg - это либо целое число, либо строка, и оба варианта охватываются более ранними случаями. Если средство проверки типов обнаружит, что вызов typing.assert_never() достижим, то он выдаст ошибку. Например, если аннотация типа для arg была вместо int | str | float, то средство проверки типов выдаст ошибку, указывающую, что unreachable имеет тип float. Чтобы вызов assert_never() прошел проверку типа, предполагаемый тип передаваемого аргумента должен быть нижним типом typing.Never и никаким другим.

Во время выполнения программы, если произошел вызов функции typing.assert_never(), поднимается исключение.

typing.reveal_type(obj, /):

Новое в Python 3.11.

Функция typing.reveal_type() (добавлена в Python 3.11.) выявляет предполагаемый статический тип выражения.

Когда средство проверки статического типа встречает вызов этой функции, она выдает диагностику с типом аргумента. Например:

x: int = 1
reveal_type(x) # Выявленный тип - 'builtins.int'

Это может быть полезно, когда нужно отладить, как программа проверки типов обрабатывает определенный фрагмент кода.

Функция возвращает свой аргумент без изменений, что позволяет использовать его в выражении:

x = reveal_type(1)  # Выявленный тип - 'builtins.int'

Большинство средств проверки типов поддерживают функцию manifest_type() в любом месте, даже если имя не импортируется из набора текста. Импорт имени из набора позволяет коду работать без ошибок во время выполнения и более четко передает намерение.

Во время выполнения программы эта функция печатает тип времени выполнения своего аргумента в stderr и возвращает его без изменений:

x = reveal_type(1)  # в `stderr` выводит "Runtime type is int"
print(x)  # печатает "1"

Декораторы модуля модуля typing.

@typing.dataclass_transform(*, eq_default=True, order_default=False, kw_only_default=False, frozen_default=False, field_specifiers=(), **kwargs):

Новое в Python 3.11.

Декоратор @typing.dataclass_transform (добавлен в Python 3.11) позволяющий пометить объект как обеспечивающий поведение, подобное классу данных.

@typing.dataclass_transform может использоваться для украшения класса, метакласса или функции, которая сама является декоратором. Наличие @dataclass_transform() сообщает средству проверки статического типа, что декорированный объект выполняет "магию" во время выполнения, которая преобразует класс, придавая ему поведение, подобное @dataclasses.dataclass().

Аргументы декоратора @dataclass_transform() можно использовать для настройки поведения декорированного класса, метакласса или функции по умолчанию:

  • eq_default: указывает, считается ли параметр eq равным True или False, если он опущен вызывающей стороной.
  • order_default: указывает, считается ли параметр order равным True или False, если он опущен вызывающей стороной.
  • kw_only_default указывает, считается ли параметр kw_only равным True или False, если он опущен вызывающей стороной.
  • frozen_default (добавлен в Python 3.12) указывает, считается ли параметр frozen равным True или False, если он опущен вызывающей стороной. По умолчанию установлено значение False.
  • field_specifiers указывает статический список поддерживаемых классов или функций, описывающих поля, аналогично dataclasses.field().
  • **kwargs (Any) произвольные аргументы других ключевых слов, чтобы обеспечить возможность возможных расширений в будущем.

    Распознанные параметры для спецификаторов полей:

    • init: указывает, должно ли поле быть включено в синтезированный метод __init__. Если не указано, то init по умолчанию имеет значение True.
    • default: предоставляет значение по умолчанию для поля.
    • default_factory: обеспечивает обратный вызов во время выполнения, который возвращает значение по умолчанию для поля. Если ни default, ни default_factory не указаны, то предполагается, что поле не имеет значения по умолчанию и должно быть предоставлено значение при создании экземпляра класса.
    • factory: - это псевдоним для default_factory.
    • kw_only: указывает, должно ли поле быть помечено только как ключевое слово. Если True, то поле будет содержать только ключевые слова. Если False, то это не будет только ключевое слово. Если не указано, то будет использоваться значение параметра kw_only для объекта, декорированного с помощью dataclass_transform, или, если он не указан, то будет использоваться значение kw_only_default для dataclass_transform.
    • alias: предоставляет альтернативное имя для поля. Это альтернативное имя используется в синтезированном методе __init__.

Во время выполнения этот декоратор записывает свои аргументы в атрибут __dataclass_transform__ оформленного объекта и не имеет никакого другого эффекта.

Пример использования:

import typing

# !!! определим `T`, если версии Python <= 3.11
T = typing.TypeVar("T")

# определяется декоратор `@create_model()`.
@typing.dataclass_transform()
def create_model(cls: type[T]) -> type[T]:
    cls.__init__ = ...
    cls.__eq__ = ...
    cls.__ne__ = ...
    return cls

# Теперь можно использовать декоратор `@create_model` 
# для создания новых классов моделей:
@create_model
class CustomerModel:
    id: int
    name: str

c = CustomerModel(id=327, name="Eric Idle")

Пример использования в базовом классе:

@dataclass_transform()
class ModelBase: ...

class CustomerModel(ModelBase):
    id: int
    name: str

Пример использования в метаклассе:

@dataclass_transform()
class ModelMeta(type): ...

class ModelBase(metaclass=ModelMeta): ...

class CustomerModel(ModelBase):
    id: int
    name: str

Определенные выше классы CustomerModel будут обрабатываться средствами проверки типов аналогично классам, созданным с помощью @dataclasses.dataclass(). Например, средства проверки типов предполагают, что эти классы имеют методы __init__(), которые принимают идентификатор и имя.

Декорированный класс, метакласс или функция могут принимать следующие логические аргументы, которые, как предполагают средства проверки типов, имеют тот же эффект, что и декоратор @dataclasses.dataclass: init, eq, order, unsafe_hash, frozen, match_args, kw_only и slots. Должна быть возможность статической оценки значений этих аргументов (True или False).

@typing.overload:

Декоратор @typing.overload() позволяет описывать функции и методы, которые поддерживают несколько различных комбинаций типов аргументов. За серией определений с @overload должно следовать ровно одно определение без @overload (для той же функции/метода).

Определения, декорированные @overload, предназначены только для проверки типов, так как они будут перезаписаны определением без @overload, в то время как последнее используется во время выполнения, но должно игнорироваться средством проверки типов. Во время выполнения прямой вызов функции с @overload вызовет исключение NotImplementedError. Пример перегрузки, которая дает более точный тип, чем можно выразить с помощью typing.Union или типов переменной:

@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <фактическая реализация>

Изменено в Python 3.11: теперь перегруженные функции можно анализировать во время выполнения с помощью @typing.get_overloads().

@typing.get_overloads(func):

Новое в Python 3.11.

Декоратор @typing.get_overloads() (добавлен в Python 3.11) возвращает последовательность определений @typing.overload - оформленные определения для функции func. Аргумент func - это объект функции для реализации перегруженной функции. Например, учитывая определение процесса в документации для @overload, @get_overloads(process) вернет последовательность из трех функциональных объектов для трех определенных перегрузок. При вызове функции без перегрузок @get_overloads() возвращает пустую последовательность.

Декоратор @typing.get_overloads() можно использовать для самоанализа перегруженной функции во время выполнения программы.

@typing.clear_overloads:

Новое в Python 3.11.

Декоратор @typing.clear_overloads() (добавлен в Python 3.11) очищает все зарегистрированные перегрузки во внутреннем реестре. Такое поведение можно использовать для освобождения памяти, используемой реестром.

@typing.final:

Новое в Python 3.8.

Декоратор @typing.final() указывает средствам проверки типов, что декорированный метод не может быть переопределен, а декорированный класс не может быть подклассом.

Например:

class Base:
    @final
    def done(self) -> None:
        ...
class Sub(Base):
    def done(self) -> None:  # Error reported by type checker
          ...

@final
class Leaf:
    ...
class Other(Leaf):  # Error reported by type checker
    ...

Проверка этих свойств во время выполнения отсутствует.

Изменено в Python 3.11: теперь декоратор устанавливает атрибут __final__ в значение True декорированного объекта. Таким образом, проверка вроде if getattr(obj, '__final__', False): может использоваться во время выполнения, чтобы определить, был ли объект obj помечен как окончательный. Если декорированный объект не поддерживает настройку атрибутов, то декоратор возвращает объект без изменений, не вызывая исключения.

@typing.no_type_check:

Декоратор @typing.no_type_check() указывает, что аннотации не являются подсказками типа.

Он работает как декоратор класса или функции. С классом, он рекурсивно применяется ко всем методам, определенным в этом классе.

Обратите внимание, что декоратор НЕ применяется к методам, определенным в его суперклассах или подклассах.

Декоратор @typing.no_type_check() изменяет функции на месте.

@typing.no_type_check_decorator:

Декоратор @typing.no_type_check_decorator() дает другому декоратору эффект @typing.no_type_check().

@typing.override:

Новое в Python 3.12.

Декоратор @typing.override указывает, что метод в подклассе предназначен для переопределения метода или атрибута в суперклассе.

Средства проверки типов должны выдавать ошибку, если метод, украшенный @override, фактически ничего не переопределяет. Это помогает предотвратить ошибки, которые могут возникнуть при изменении базового класса без эквивалентного изменения дочернего класса.

Например:

from typing import override

class Base:
  def get_color(self) -> str:
    return "blue"

class GoodChild(Base):
  # ок: класс переопределяет Base.get_color
  @override
  def get_color(self) -> str:
    return "yellow"

class BadChild(Base):
  # ошибка проверки типа: класс не переопределяет Base.get_color
  @override  
  def get_colour(self) -> str:
    return "red"

Проверка во время выполнения не выполняется.

Декоратор попытается установить для атрибута __override__ значение True на декорируемом объекте. Таким образом, проверку типа getattr(obj, '__override__', False) можно использовать во время выполнения, чтобы определить, был ли объект obj помечен как переопределяющий. Если декорированный объект не поддерживает установку атрибутов, то декоратор возвращает объект без изменений, не вызывая исключения.

@typing.type_check_only:

Декоратор @typing.type_check_only() помечает класс или функцию как недоступные во время выполнения.

Этот декоратор сам по себе недоступен во время выполнения. В основном он предназначен для маркировки классов, определенных в файлах-заглушках типов, если реализация возвращает экземпляр частного класса:

@type_check_only
class Response:  # частный или недоступный во время выполнения
    code: int
    def get_header(self, name: str) -> str: ...

def fetch_response() -> Response: ...

Обратите внимание, что возвращать экземпляры закрытых классов не рекомендуется. Обычно предпочтительнее делать такие классы публичными.