You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为接收类型注解作为输入并返回对应注解类型值的Python函数添加正确类型标注?

如何为接收类型注解作为输入并返回对应注解类型值的Python函数添加正确类型标注?

我想给一个函数添加类型标注,这个函数接收一个合法的类型注解作为输入参数,返回值的类型和这个注解一致。它不仅要支持type的实例,还要支持像多类型联合或者带标注的类型这类特殊形式。

(底层逻辑是这个函数通过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"

但目前这个实现只支持output_type是实际的type对象的情况,不支持一般的类型注解。用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 `<types.UnionType special-form 'int | str'>`
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 `<special-form 'typing.Annotated[int, <metadata>]'>`
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", "<typing special form>"  [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)

我想给convert函数添加正确的类型标注,同时不改变它的逻辑行为。

这个问题并不是重复问题——之前有个类似问题的解决方案只支持具体的type类型,不支持一般的类型注解。我是用那个方案作为起点的,但现在需要一个能支持所有类型注解的解决方案,类似Pydantic本身或者typing.cast()函数的行为。

可能问题的根源在于我写的output_type: type[T]标注是错误的,我不知道该如何给“类型注解”这个概念添加类型标注。

备注:内容来源于stack exchange,提问作者palotasb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 18:04:36