Python3 аннотации типа для функции генерации типа - PullRequest
0 голосов
/ 25 марта 2020

Я немного озадачен аннотациями типов в 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, но я сомневаюсь в этом, так как он очень хорошо работает для стандартной библиотеки, которая в значительной степени использует одинаково сложные аннотации типов.


Простой пример, где вывод типа кажется неудачным:

Example of failing syntax highlighting

Обратите внимание, как это отличается от этой версии списка:

Example of working syntax highlighting


У меня также много вопросов о том, что на самом деле делает 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

Не думаю, что это что-то добавляет к вопросу, но здесь вы go: D

1 Ответ

0 голосов
/ 25 марта 2020

TLDR: используйте Callable вместо Type для создания экземпляров любого типа. В спецификациях c следует явно указать сигнатуру возвращаемого типа.

def TypeSequence(
    usertype: Type[UserType]
) -> Callable[[Iterable[UserType]], Sequence[UserType]]
    ...

A Type[Sequence[UserType]] не может быть создан, поскольку Sequence является абстрактным типом. mypy помечает экземпляр как недействительный:

XSeq = TypeSequence(X)
x_seq = XSeq([X()])  # error: Too many arguments for "Sequence"

Чтобы быть верным с типом, аннотируйте возвращаемый тип как List или UserList.

def TypeSequence(usertype: Type[UserType]) -> Type[UserList[UserType]]:
    ...

поверх типа -правильно, имейте в виду, что PyCharm обычно не понимает сложные Type отношения. Раскрытие типа функции показывает, что Type[UserList[UserType]] упрощается до Type[UserList].

Использование Callable вместо этого позволяет express создание экземпляра сложного типа. Точная подпись может быть определена, включая Sequence вместо UserList:

def TypeSequence(usertype: Type[UserType]) -> Callable[[Iterable[UserType]], Sequence[UserType]]:
    ...
...