Как аннотировать функцию, которая принимает аннотацию типа в качестве входных данных и применять ее к выходным данным?Python

Программы на Python
Ответить
Anonymous
 Как аннотировать функцию, которая принимает аннотацию типа в качестве входных данных и применять ее к выходным данным?

Сообщение Anonymous »

Я хочу аннотировать тип функции, которая принимает допустимую аннотацию типа в качестве входного параметра и возвращает значение, аннотированное типом той же аннотации. Он должен поддерживать не только экземпляры типа, но и специальные формы, такие как объединения нескольких типов или аннотированные типы.
(Внутри функция преобразует значение в заданный тип с помощью Pydantic. В приведенном ниже примере нетипизированное значение — это параметр input_value, но в реальном коде оно возвращается API.)
Я хочу, чтобы следующий код работал:

Код: Выделить всё

from typing import Annotated, Any, TypeVar, overload
from typing_extensions import assert_type

from pydantic import TypeAdapter

T = TypeVar("T")

@overload
def convert(value: Any) -> Any:
...

@overload
def convert(value: Any, output_type: type[T]) -> T:
...

def convert(value: Any, output_type: type[T] | Any = Any) -> T:
adapter = TypeAdapter(output_type)
return adapter.validate_python(value)

assert_type(convert(1), Any)

assert_type(convert(1, int), int)

assert_type(convert(1, int | str), int | str)
# "assert_type" mismatch: expected "int | str" but received "Unknown"

assert_type(convert(1, Annotated[int, "foo"]), Annotated[int, "foo"])
# Argument of type "Annotated" cannot be assigned to parameter "output_type" of type "type[T@convert]" in function "convert"
#   Type "Annotated" is not assignable to type "type[T@convert]"
# "assert_type" mismatch: expected "int" but received "Unknown"
Однако это работает только для значений выходного_типа, которые являются фактическими объектами типа, а не аннотациями типов в целом. При использовании Pyright происходит сбой со встроенными ошибками, показанными выше. Другие средства проверки типов выдают следующий результат.

Код: Выделить всё

ty check typing_test.py:
error[type-assertion-failure]: Argument does not have asserted type `int | str`
--> typing_test.py:24:1
|
22 | assert_type(convert(1, int), int)
23 |
24 | assert_type(convert(1, int | str), int | str)
| ^^^^^^^^^^^^---------------------^^^^^^^^^^^^
|             |
|             Inferred type is `Unknown`
25 | # "assert_type" mismatch: expected "int | str" but received "Unknown"
|
info: `int | str` and `Unknown` are not equivalent types
info: rule `type-assertion-failure` is enabled by default

error[invalid-argument-type]: Argument to function `convert` is incorrect
--> typing_test.py:24:24
|
22 | assert_type(convert(1, int), int)
23 |
24 | assert_type(convert(1, int | str), int | str)
|                        ^^^^^^^^^ Expected `type[Unknown]`, found ``
25 | # "assert_type" mismatch: expected "int | str" but received "Unknown"
|
info: Matching overload defined here
--> typing_test.py:13:5
|
12 | @overload
13 | def convert(object: Any, output_type: type[T]) -> T:
|     ^^^^^^^              -------------------- Parameter declared here
14 |     ...
|
info: Non-matching overloads for function `convert`:
info:   (object: Any) -> Any
info: rule `invalid-argument-type` is enabled by default

error[type-assertion-failure]: Argument does not have asserted type `int`
--> typing_test.py:27:1
|
25 | # "assert_type" mismatch: expected "int | str" but received "Unknown"
26 |
27 | assert_type(convert(1, Annotated[int, "foo"]), Annotated[int, "foo"])
| ^^^^^^^^^^^^---------------------------------^^^^^^^^^^^^^^^^^^^^^^^^
|             |
|             Inferred type is `Unknown`
28 | # Argument of type "Annotated" cannot be assigned to parameter "output_type" of type "type[T@convert]" in function "convert"
29 | #   Type "Annotated" is not assignable to type "type[T@convert]"
|
info: `int` and `Unknown` are not equivalent types
info: rule `type-assertion-failure` is enabled by default

error[invalid-argument-type]: Argument to function `convert` is incorrect
--> typing_test.py:27:24
|
25 | # "assert_type" mismatch: expected "int | str" but received "Unknown"
26 |
27 | assert_type(convert(1, Annotated[int, "foo"]), Annotated[int, "foo"])
|                        ^^^^^^^^^^^^^^^^^^^^^ Expected `type[Unknown]`, found ``
28 | # Argument of type "Annotated" cannot be assigned to parameter "output_type" of type "type[T@convert]" in function "convert"
29 | #   Type "Annotated" is not assignable to type "type[T@convert]"
|
info: Matching overload defined here
--> typing_test.py:13:5
|
12 | @overload
13 | def convert(object: Any, output_type: type[T]) -> T:
|     ^^^^^^^              -------------------- Parameter declared here
14 |     ...
|
info: Non-matching overloads for function `convert`:
info:   (object: Any) -> Any
info: rule `invalid-argument-type` is enabled by default

Found 4 diagnostics

Код: Выделить всё

mypy typing_test.py:
typing_test.py:24: error: Expression is of type "int", not "int | str"  [assert-type]
assert_type(convert(1, int | str), int | str)
^
typing_test.py:24: error: Argument 2 to "convert" has incompatible type "UnionType | type[int]"; expected "type[int]"  [arg-type]
assert_type(convert(1, int | str), int | str)
^~~~~~~~~
typing_test.py:27: error: Expression is of type "Any", not "int"  [assert-type]
assert_type(convert(1, Annotated[int, "foo"]), Annotated[int, "foo"])
^
typing_test.py:27: error: No overload variant of "convert" matches argument types "int", ""  [call-overload]
assert_type(convert(1, Annotated[int, "foo"]), Annotated[int, "foo"])
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typing_test.py:27: note: Possible overload variants:
typing_test.py:27: note:     def convert(object: Any) ->  Any
typing_test.py:27: note:     def [T] convert(object: Any, output_type: type[T]) -> T
Found 4 errors in 1 file (checked 1 source file)
Я ищу правильные аннотации типов в функции преобразования без изменения ее логического поведения.
Это не дубликат Python: ввод универсальной функции, которая получает тип и возвращает экземпляр этого типа, потому что этот вопрос (и решение) работает только для конкретных типов-s, но не работает с аннотациями типов в целом. Я использовал то же решение в качестве отправной точки, но я ищу решение, которое также поддерживает любые аннотации, аналогично самому pydantic или функции typing.cast().
Какую аннотацию типа использовать для аннотации типа? может быть связано (возможно, основная причина в том, что моя аннотация output_type: type[T] неверна, и я не знаю, как аннотировать тип аннотации типа.

Подробнее здесь: https://stackoverflow.com/questions/799 ... d-apply-it
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»