Аннотации типов в Python
typing.TypeVar является универсальным типом завода. Его основная цель — служить параметром / заполнителем для аннотаций обобщенной функции / класса / метода:
T = typing.TypeVar («T»)
def get_first_element (l: typing.Sequence [T]) -> T: «» «Получает первый элемент последовательности.» «» return l [0]
Добавление типов в функцию
Давайте рассмотрим пример функции, которая получает два аргумента и возвращает значение, указывающее их сумму:
def two_sum(a, b): return a + b
Глядя на этот код, один не может безопасно и без сомнения указать тип аргументов для функции two_sum .Он работает как при поставке с int значения:
print(two_sum(2, 1)) # result: 3
print(two_sum("a", "b")) # result: "ab"
а также с другими значениями, например, list с, tuple ов и так далее.
Из-за этой динамической природы типов Python, где многие из них применимы для данной операции, любая программа проверки типов не сможет обоснованно утверждать, следует ли разрешить вызов этой функции или нет.
Чтобы помочь нашей проверке типов, мы можем теперь предоставить подсказки для нее в определении функции, указывающие тип, который мы разрешаем.
Для того, чтобы указать , что мы хотим , чтобы int типы мы можем изменить наше определение функции выглядеть следующим образом :
def two_sum(a: int, b: int): return a + b
Аннотации следовать имя аргумента и отделены друг от друга : характер.
Точно так же, чтобы указать только str тип разрешен, мы бы изменить нашу функцию , чтобы определить его:
def two_sum(a: str, b: str): return a + b
Помимо указания типа аргументов, можно также указать возвращаемое значение вызова функции. Это делается путем добавления -> символа с последующим типом после закрывающей скобки в списке аргументов , но до того , как : в конце объявления функции:
def two_sum(a: int, b: int) -> int: return a + b
Теперь мы показали , что возвращаемое значение при вызове two_sum должно быть типа int .Точно так же мы можем определить соответствующие значения для str , float , list , set и другие.
Хотя подсказки типов в основном используются средствами проверки типов и средами разработки, иногда вам может потребоваться получить их. Это может быть сделано с помощью __annotations__ специального атрибута:
two_sum.__annotations__ # , 'b': , 'return': >
Члены класса и методы
class A: x = None # type: float def __init__(self, x: float) -> None: """ self should not be annotated init should be annotated to return None """ self.x = x @classmethod def from_int(cls, x: int) -> 'A': """ cls should not be annotated Use forward reference to refer to current class with string literal 'A' """ return cls(float(x))
Прямая ссылка на текущий класс необходима, так как аннотации оцениваются, когда функция определена. Прямые ссылки также можно использовать при обращении к классу, который при импорте вызывает циклический импорт.
Переменные и атрибуты
Переменные комментируются с помощью комментариев:
x = 3 # type: int x = negate(x) x = 'a type-checker might catch this error'
Начиная с Python 3.6, есть также новый синтаксис для переменных аннотаций.Код выше может использовать форму
x: int = 3
В отличие от комментариев, также можно просто добавить подсказку типа в переменную, которая не была ранее объявлена, без установки значения:
y: int
Кроме того , если они используются в модуле или на уровне класса, намеки типа могут быть получены с помощью typing.get_type_hints(class_or_module) :
class Foo: x: int y: str = 'abc' print(typing.get_type_hints(Foo)) # ChainMap(, 'y': >, <>)
Кроме того , они могут быть доступны с помощью __annotations__ специальной переменной или атрибута:
x: int print(__annotations__) # > class C: s: str print(C.__annotations__) # >
NamedTuple
Создание namedtuple с намеками типа осуществляется с помощью функции NamedTuple из typing модуля:
import typing Point = typing.NamedTuple('Point', [('x', int),('y', int)])
Обратите внимание, что имя результирующего типа является первым аргументом функции, но его следует назначить переменной с тем же именем, чтобы упростить работу контролеров типов.
Введите подсказки для аргументов ключевых слов
def hello_world(greeting: str = 'Hello'): print(greeting + ' world!')
Обратите внимание на пробелы вокруг знака равенства, в отличие от того, как обычно вводятся ключевые аргументы.
Типизация абстрактных базовых классов
Рассмотренные здесь типы аннотаций абстрактных базовых классов соответствуют встроенным коллекциям, представленным в модуле collections.abc .
С версии Python 3.9 для всех рассмотренных типов аннотаций не рекомендован импорт из модуля typing , так как теперь collections.abc. поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
Типы аннотаций абстрактных базовых классов:
- typing.AbstractSet() устарело с версии Python 3.9,
- typing.ByteString() устарело с версии Python 3.9,
- typing.Collection() устарело с версии Python 3.9,
- typing.Container() устарело с версии Python 3.9,
- typing.ItemsView() устарело с версии Python 3.9,
- typing.KeysView() устарело с версии Python 3.9,
- typing.Mapping() устарело с версии Python 3.9,
- typing.MappingView() устарело с версии Python 3.9,
- typing.MutableMapping() устарело с версии Python 3.9,
- typing.MutableSequence() устарело с версии Python 3.9,
- typing.MutableSet() устарело с версии Python 3.9,
- typing.Sequence() устарело с версии Python 3.9,
- typing.ValuesView() устарело с версии Python 3.9,
- typing.Iterable() устарело с версии Python 3.9,
- typing.Iterator() устарело с версии Python 3.9,
- typing.Generator() устарело с версии Python 3.9,
- typing.Hashable устарело с версии Python 3.12,
- typing.Reversible() устарело с версии Python 3.9,
- typing.Sized устарело с версии Python 3.12,
- typing.Coroutine() устарело с версии Python 3.9,
- typing.AsyncGenerator() устарело с версии Python 3.9,
- typing.AsyncIterable() устарело с версии Python 3.9,
- typing.AsyncIterator() устарело с версии Python 3.9,
- typing.Awaitable() устарело с версии Python 3.9,
- typing.ContextManager() устарело с версии Python 3.9,
- typing.AsyncContextManager() устарело с версии Python 3.9.
typing.AbstractSet(Sized, Collection[T_co]) :
Класс typing.AbstractSet() общая версия абстрактного базового класса collections.abc.Set .
Устарело с Python 3.9: теперь collections.abc.Set поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.ByteString(Sequence[int]) :
Класс typing.ByteString() общая версия абстрактного базового класса collections.abc.ByteString .
Этот тип представляет типы bytes , bytearray , и memoryview .
В качестве сокращения для этого типа, bytes могут использоваться для аннотирования аргументов любого из упомянутых выше типов.
Устарело с Python 3.9: теперь collections.abc.ByteString поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Collection(Sized, Iterable[T_co], Container[T_co]) :
Класс typing.Collection() общая версия абстрактного базового класса collections.abc.Collection .
Новое в Python 3.6.0.
Устарело с Python 3.9: теперь collections.abc.Collection поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Container(Generic[T_co]) :
Класс typing.Container() общая версия абстрактного базового класса collections.abc.Container .
Устарело с Python 3.9: теперь collections.abc.Container поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.ItemsView(MappingView, Generic[KT_co, VT_co]) :
Класс typing.ItemsView() общая версия абстрактного базового класса collections.abc.ItemsView .
Устарело с Python 3.9: теперь collections.abc.ItemsView поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.KeysView(MappingView[KT_co], AbstractSet[KT_co]) :
Класс typing.KeysView() общая версия абстрактного базового класса collections.abc.KeysView .
Устарело с Python 3.9: теперь collections.abc.KeysView поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Mapping(Sized, Collection[KT], Generic[VT_co]) :
Класс typing.Mapping() общая версия абстрактного базового класса collections.abc.Mapping .
Этот тип можно использовать следующим образом:
def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: return word_list[word]
Устарело с Python 3.9: теперь collections.abc.Mapping поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.MappingView(Sized, Iterable[T_co]) :
Класс typing.MappingView() общая версия абстрактного базового класса collections.abc.MappingView .
Устарело с Python 3.9: теперь collections.abc.MappingView поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.MutableMapping(Mapping[KT, VT]) :
Класс typing.MutableMapping() общая версия абстрактного базового класса collections.abc.MutableMapping .
Устарело с Python 3.9: теперь collections.abc.MutableMapping поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.MutableSequence(Sequence[T]) :
Класс typing.MutableSequence() общая версия абстрактного базового класса collections.abc.MutableSequence .
Устарело с Python 3.9: теперь collections.abc.MutableSequence поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.MutableSet(AbstractSet[T]) :
Класс typing.MutableSet() общая версия абстрактного базового класса collections.abc.MutableSet .
Устарело с Python 3.9: теперь collections.abc.MutableSet поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Sequence(Reversible[T_co], Collection[T_co]) :
Класс typing.Sequence() общая версия абстрактного базового класса collections.abc.Sequence .
Устарело с Python 3.9: теперь collections.abc.Sequence поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.ValuesView(MappingView[VT_co]) :
Класс typing.ValuesView() общая версия абстрактного базового класса collections.abc.ValuesView .
Устарело с Python 3.9: теперь collections.abc.ValuesView поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
Corresponding to other types in collections.abc
typing.Iterable(Generic[T_co]) :
Класс typing.Iterable() общая версия абстрактного базового класса collections.abc.Iterable .
Устарело с Python 3.9: теперь collections.abc.Iterable поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Iterator(Iterable[T_co]) :
Класс typing.Iterator() общая версия абстрактного базового класса collections.abc.Iterator .
Устарело с Python 3.9: теперь collections.abc.Iterator поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]) :
Генератор может быть аннотирован общим типом Generator[YieldType, SendType, ReturnType] .
def echo_round() -> Generator[int, float, str]: sent = yield 0 while sent >= 0: sent = yield round(sent) return 'Done'
Обратите внимание, что в отличие от многих других универсальных шаблонов в модуле typing , SendType генератора ведет себя контравариантно, а не ковариантно или инвариантно.
Если генератор будет выдавать только значения, установите для SendType и ReturnType значение None :
def infinite_stream(start: int) -> Generator[int, None, None]: while True: yield start start += 1
В качестве альтернативы, отметьте генератор как имеющий тип возвращаемого значения Iterable[YieldType] или Iterator[YieldType] :
def infinite_stream(start: int) -> Iterator[int]: while True: yield start start += 1
Устарело с Python 3.9: теперь collections.abc.Generator поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Hashable :
Атрибут typing.Hashable псевдоним для абстрактного базового класса collections.abc.Hashable .
Устарело с Python 3.12: вместо этого необходимо использовать напрямую Collections.abc.Hashable .
typing.Reversible(Iterable[T_co]) :
Класс typing.Reversible() общая версия абстрактного базового класса collections.abc.Reversible .
Устарело с Python 3.9: теперь collections.abc.Reversible поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Sized :
Атрибут typing.Sized псевдоним для абстрактного базового класса collections.abc.Sized .
Устарело с Python 3.12: вместо этого необходимо использовать напрямую Collections.abc.Sized .
Типы аннотаций для асинхронных программ.
typing.Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co]) :
Класс typing.Coroutine() общая версия абстрактного базового класса collections.abc.Coroutine .
Варианты и порядок типов переменных соответствуют переменным генератора, например:
from collections.abc import Coroutine c = None # type: Coroutine[list[str], str, int] . x = c.send('hi') # type: list[str] async def bar() -> None: x = await c # type: int
Устарело с Python 3.9: теперь collections.abc.Reversible поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra]) :
Асинхронный генератор может быть аннотирован общим типом AsyncGenerator[YieldType, SendType] .
async def echo_round() -> AsyncGenerator[int, float]: sent = yield 0 while sent >= 0.0: rounded = await round(sent) sent = yield rounded
В отличие от обычных генераторов, асинхронные генераторы не могут возвращать значение, поэтому параметр типа ReturnType отсутствует. Как и в случае с генератором, SendType ведет себя контравариантно.
Если генератор будет выдавать только значения, установите для параметра SendType значение None :
async def infinite_stream(start: int) -> AsyncGenerator[int, None]: while True: yield start start = await increment(start)
В качестве альтернативы отметьте генератор как имеющий возвращаемый тип AsyncIterable[YieldType] или AsyncIterator[YieldType] :
async def infinite_stream(start: int) -> AsyncIterator[int]: while True: yield start start = await increment(start)
Устарело с Python 3.9: теперь collections.abc.AsyncGenerator поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.AsyncIterable(Generic[T_co]) :
Класс typing.AsyncIterable() общая версия абстрактного базового класса collections.abc.AsyncIterable .
Не рекомендуется с Python 3.9: теперь collections.abc.AsyncIterable поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.AsyncIterator(AsyncIterable[T_co]) :
Класс typing.AsyncIterator() общая версия абстрактного базового класса collections.abc.AsyncIterator .
Устарело с Python 3.9: теперь collections.abc.AsyncIterator поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.Awaitable(Generic[T_co]) :
Класс typing.Awaitable() общая версия абстрактного базового класса collections.abc.Awaitable .
Устарело с Python 3.9: теперь collections.abc.Awaitable поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
Типы аннотаций диспетчера контекста
typing.ContextManager(Generic[T_co]) :
Класс typing.ContextManager() общая версия абстрактного базового класса collections.AbstractContextManager .
Устарело с Python 3.9: теперь collections.abc.AbstractContextManager поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
typing.AsyncContextManager(Generic[T_co]) :
Класс typing.AsyncContextManager() общая версия абстрактного базового класса collections.AbstractAsyncContextManager .
Устарело с Python 3.9: теперь collections.abc.AbstractAsyncContextManager поддерживает синтаксис аннотации [] . Смотрите GenericAlias .
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Аннотация Any модуля typing
- Аннотации Never и NoReturn модуля typing
- Тип аннотации TypeAlias модуля typing
- Аннотация LiteralString модуля typing
- Аннотация Self модуля typing
- Аннотации Required и NotRequired модуля typing
- Тип аннотации Union модуля typing
- Тип аннотации Optional модуля typing
- Тип аннотации Tuple() модуля typing
- Тип аннотации Callable() модуля typing
- Тип аннотации Concatenate модуля typing
- Класс ParamSpec модуля typing
- Тип аннотации TypeGuard модуля typing
- Класс Type() модуля typing
- Тип аннотации Literal модуля typing
- Тип аннотации ClassVar модуля typing
- Тип аннотации Final() модуля typing
- Тип аннотации Annotated модуля typing
- Тип аннотации Generic модуля typing
- Тип аннотации TypeVar модуля typing
- Аннотация TypeVarTuple модуля typing
- Тип аннотации Unpack модуля typing
- Тип аннотации AnyStr модуля typing
- Тип аннотации Protocol() модуля typing
- Декоратор @runtime_checkable модуля typing
- Тип аннотации NamedTuple модуля typing
- Класс NewType модуля typing
- Тип аннотации TypedDict() модуля typing
- Типы аннотаций коллекций модуля typing
- Аннотация абстрактных базовых классов
- Функции и декораторы модуля typing
- Помощники самоанализа модуля typing
- ParamSpecArgs и ParamSpecKwargs модуля typing
- Класс TypeAliasType модуля typing
Аннотация типов в классе
Тут captain и damage — объявлены с аннотациями для атрибутов объекта (instance), третий вариант — с аннотацией для переменной класса. Правда, у captain значение по умолчанию делает этот атрибут переменной класса. Но в принципе инициализация объектами неизменяемых типов вполне допустима (первое переписваивание атрибута у объекта перекроет значение атрибута класса). С изменяемыми типами (например, списками) нужно быть осторожнее.
Таким образом, нужно объявить тип вашего поля на верхнем уровне класса:
class Node: __x: int def __init__(self, x: int) -> None: self.__x = x
Если попытаться присвоить значение другого типа, при проверке с помощью mypy выведется ошибка:
class Node: __x: int def __init__(self, x: float) -> None: self.__x = x
❯ mypy test.py test.py:5: error: Incompatible types in assignment (expression has type "float", variable has type "int") Found 1 error in 1 file (checked 1 source file)
PyCharm также подсветит проблему:
Как делается аннотация классов в python
Аннотация функций
Синтаксис аннотации переменных работает и для параметров функций. Однако, чтобы указать тип возврата ( return ), мы добавляем стрелку –> , за которой следует его тип.
from typing import Dict, List def convert_celcius_to_fahrenheit(celcius_temp: float) –> float: return (celcius_temp * 9/5) + 32 def send_email(subject: str, body: str, recipients: List[str], cache: Dict[str, str]) –> bool: # пропущено для краткости return True # или False
Использование специальных типов
Итак, когда мы разогрелись и познакомились с синтаксисом аннотаций типов, давайте познакомимся с более сложными типами.
Any
Переменная типа Any является неограниченной. Поэтому такие переменные совместимы со всеми другими типами ( int , str , List и т. д.), а все остальные типы совместимы с ними.
from typing import Any result: Any = "SUCCESS" # также работает, потому что переменные типа Any совместимы с другими типами result = 10 state: str = "PENDING" # работает, потому что все остальные типы совместимы с типом Any. state = result
Literal
Литералы используются для указания программам проверки типов, что значение, которое имеет переменная или функция, равно одному из указанных значений.
from typing import Literal GENDER = Literal["male", "female", "non–conforming"] def create_user(first_name: str, last_name: str, gender: GENDER) –> dict[str, str, GENDER]: return create_user("John", "Bond", "male")
В вышеприведенном примере пол будет одним из значений литерального объявления GENDER – «мужской», «женский» или «non–conforming».
Union
Иногда переменная может обладать свойствами, охватывающими два объявленных типа. Переменная также может быть двух типов.
from typing import Union def get_room_temperature() –> Union[int, float]: return 20.8 # 20 тоже сработает
TypedDict
Словари, будучи одной из самых простых форм структуры данных в Python, являются одним из наиболее используемых типов переменных в языке.
Использование TypedDict может значительно улучшить читаемость кода, особенно в большом проекте, где много объявлений в разных местах; отслеживание того, что куда идет, становится затруднительным по мере изменения размера проекта.
from typing import TypedDict, Union class Card(TypedDict): rank: Union[str, int] suit: str # класс Card теперь имеет поведение обоих классов TypedDict и dict # Card может быть использован для аннотации переменной ace_of_spade: Card = # или может быть инстанцирован ace_of_spade = Card(rank='A', suit='♤')
NoReturn
Тип NoReturn аналогичен типу void в других языках программирования. Он используется для объявления того, что функция не имеет возврата.
from typing import NoReturn def say_greeting() –> NoReturn: print("Hello World!")
Final
Это конструкция типизации, используемая для указания того, что переменная не должна быть повторно назначена или переопределена в подклассе.
from typing import Final MIN_NAME_LENGTH: Final = 2 # выдаст ошибку, зафиксированную системой проверки типов MIN_NAME_LENGTH += 1 class Validator(object): MIN_NAME_LENGTH: Final[int] = 4 class UserValidator(Validator): # эта строка будет отмечена интерпретатором MIN_NAME_LENGTH = 3
Использование статической проверки типов в Python
Интерпретатор Python по умолчанию не осуществляет проверку типов. Однако была создана версия интерпретатора Python – mypy , которая обеспечивает проверку типов на уровне интерпретатора.
Вы можете использовать mypy двумя способами:
- Загрузить командную строку mypy и использовать ее для запуска ваших скриптов Python.
- Установить расширение mypy , доступное в VSCode и PyCharm.
Лучшие практики аннотации типов
1. Использование типа Any
Тип Any следует использовать только тогда, когда точный тип возвращаемой переменной или параметра функции нам неизвестен; это может быть при использовании сторонней библиотеки, не имеющей аннотаций типов, или при использовании модуля без аннотаций типов.
2. Включите статическую проверку типов
Преимущества проверки типов, заключающиеся в предотвращении ошибок и помощи разработчику, будут не так ощутимы, если она будет динамической. Если вы не любите командную строку mypy , вы также можете установить его как расширение VSCode или PyCharm.
3. Используйте кортежи для массивов фиксированной длины
Кортежи выполняют двойную функцию записи. Поэтому, когда у вас есть известное количество элементов в массиве, особенно когда они не все одного типа, для переменной лучше использовать тип кортеж.
4. Типы возврата функций
Функции должны выполнять одно и только одно действие, поэтому они должны иметь один определенный тип.
В этой статье мы научились:
- Синтаксису аннотации типов, а также аннотации переменных и функций.
- Как использовать сложные конструкции типизации ( Any , Literal , Union , TypedDict , NoReturn , Final ).
- Как можно обеспечить проверку типов на уровне интерпретатора Python.
- Лучшим практикам аннотации типов и как внедрить проверку типов Python в свой проект.
Материалы по теме
- Словари в Python: 12 задач для начинающих с решениями
- Дорожная карта Python-разработчика
- 28 лучших каналов YouTube про Python для начинающих
