Я немного запутался в аннотациях типов в python3, особенно для функции генератора, которая выдает сгенерированные типы. Я думаю, что именно моя путаница связана с документацией typing.Type
а>. Вот мой фрагмент кода:
from collections import UserList
UserType = TypeVar('UserType')
def TypeSequence(usertype: Type[UserType]) -> Type[Sequence[UserType]]:
class Result(UserList):
... # Cut out the implementation for brevity's sake
return Result
Сгенерированный «TypeSequence» что-то делает с проверками типов, чтобы генерировать только сериализуемые структуры данных, что не важно для этого вопроса. Дело в том, что вы должны иметь возможность сделать что-то вроде этого:
MyIntSequence = TypeSequence(int)
MyIntSequence((1, 2, 3)) -> [1, 2, 3] with type Sequence[Int]
MyTupleSequence = TypeSequence(tuple)
MyTupleSequence(((1, 2), (3, 4))) -> [(1, 2), (3, 4)] with type Sequence[tuple]
Мой вопрос. Верны ли предоставленные мной аннотации типов?
Мои сомнения связаны в основном с PyCharm, который не может предоставить типы, сгенерированные моей пользовательской функцией генератора. Может быть проблема с PyCharm, но я в этом сомневаюсь, поскольку он очень хорошо работает со стандартной библиотекой, которая в значительной степени использует столь же сложные аннотации типов.
Простой пример, когда вывод типа кажется неудачным:
Обратите внимание, как это отличается от этой версии списка:
Я также получаю много вопросов о том, что на самом деле делает TypeSequence. Я отредактировал эту реализацию, чтобы сделать пост более кратким, но здесь полная реализация. Он выполняет некоторые проверки типов и типов:
from collections import UserList
from typing import (Optional, Any, Sequence, Callable, Hashable, Dict, Mapping, Type, TypeVar,
)
UserType = TypeVar('UserType')
def TypeSequence(usertype: Type[UserType]) -> Type[Sequence[UserType]]:
class Result(UserList):
def __init__(self, *args):
from collections import Iterable
if len(args) == 0:
super(Result, self).__init__()
elif len(args) == 1:
if not isinstance(args[0], Iterable):
raise ValueError("Not a iterable")
if issubclass(usertype, tuple) and hasattr(usertype, "_fields"):
if any(not isinstance(x, Iterable) for x in args[0]):
raise ValueError("Invalid initializer for named tuple")
if len(args[0]) != len(usertype._fields):
raise ValueError(f"Not enough values to initialize {usertype}")
seq = (usertype(*x) for x in args[0])
else:
seq = (usertype(x) for x in args[0])
super(Result, self).__init__(seq)
Result.__name__ = f"TypeSequence[{usertype.__name__}]"
return Result
Я не думаю, что это что-то добавляет к вопросу, но вот: D
UserList
? Это не определено. - person a_guest   schedule 25.03.2020list
. - person Wombatz   schedule 25.03.2020TypeSequence
? Кажется, это не связано с определением функции-генератора в Python, которая используетyield
для создания значения типаgenerator
. - person chepner   schedule 25.03.2020UserList
, а не просто возвращать подклассlist
? Тогда ваш возвращаемый тип может быть простоType[List[UserType]]
. - person chepner   schedule 25.03.2020Result(UserList)
? Класс не имеет никакой дополнительной функциональности по сравнению с обычнымlist
. Фабричная функция формыCallable[[Iterable[T]], List[T]]
кажется более подходящей, чем класс. - person MisterMiyagi   schedule 25.03.2020Mypy
правильно выводит типx_seq
, но отвергаетXSeq([X()])
—Sequence
не принимает никаких аргументов. В принципе, поведение дальнейшего кода для проверки типов не определено. ИспользованиеList
вместоSequence
делает ваш код хорошо типизированным, а использованиеCallable
вместоType
(как в связанном вопросе) также удовлетворяет PyCharm.def TypeSequence(usertype: Callable[..., UserType]) -> Callable[[Iterable[UserType]], Sequence[UserType]]
. - person MisterMiyagi   schedule 25.03.2020