【问题标题】:Python Typing: declare return value type based on function argumentPython Typing:根据函数参数声明返回值类型
【发布时间】:2020-05-28 20:35:32
【问题描述】:

假设我有一个以类型为参数并返回该类型实例的函数:

def fun(t):
    return t(42)

然后我可以调用它并获取提供类型的对象:

fun(int)           # 42
fun(float)         # 42.0
fun(complex)       # (42+0j)
fun(str)           # "42"
fun(MyCustomType)  # something

该列表并不详尽,我希望能够使用具有适当构造函数的任何类型。

然后,我想为该函数添加类型提示。该函数返回值的类型提示应该是什么?


我试过using simply t,因为t是一种类型:

def fun(t: type) -> t:
    return t(42)

但这不起作用:

main.py:1:错误:未定义名称“t”


This answer 建议using a TypeVar

from typing import TypeVar

T = TypeVar("T")

def fun(t: T) -> T:
    return t(42)

但这似乎不对,因为T 表示一个类型,所以它表明返回的是类型本身,而不是它的实例。 Mypy 拒绝它:

main.py:6: 错误:“对象”不可调用


Using Any 明明有效,但我觉得太模糊了,没有传达意图:

from typing import Any

def fun(t: type) -> Any:
    return t(42)

【问题讨论】:

    标签: python python-3.x type-hinting


    【解决方案1】:

    TLDR:您需要一个TypeVar 来表示调用的返回类型 t

    def fun(t: Callable[[int], R]) -> R:
        ...
    

    此处对类型的限制过于严格。该函数接受任何采用整数的Callable,函数的返回类型是Callable 的返回类型。这可以使用 TypeVar 作为返回类型来指定:

    from typing import Callable, TypeVar
    
    
    R = TypeVar('R')  # the variable return type
    
    
    def fun(t: Callable[[int], R]) -> R:
        return t(42)
    
    fun(int)                            # Revealed type is 'builtins.int*'
    fun(float)                          # Revealed type is 'builtins.float*'
    reveal_type(fun(lambda x: str(x)))  # Revealed type is 'builtins.str*'
    

    这也适用于类型,因为类型实例化是一个调用。

    如果是更复杂的签名,例如如果需要关键字参数,请使用Protocol(来自typingtyping_extensions)。


    请注意,如果明确希望仅将42 传递给Callable,则可以使用Literal(来自typingtyping_extensions)来指定。

    R = TypeVar('R')
    
    
    def fun(t: Callable[[Literal[42]], R]) -> R:
        return t(42)
    

    请注意,Callable[[int], R] 类型的任何函数也满足 Callable[[Literal[42]], R]

    【讨论】:

      【解决方案2】:

      您正在寻找typing.Type,所以大意是:

      from typing import TypeVar, Type
      
      T = TypeVar("T", str, complex, float, int)
      
      def fun(t: Type[T]) -> T:
          return t(42)
      
      fun(int)
      fun(float)
      fun(complex)
      fun(str)
      

      请注意,您的类型变量需要受到限制,因为并非所有 Type 对象都接受参数,但您可以将其限制为与您的示例类似的几个。

      【讨论】:

      • 谢谢,这确实有效,但我觉得约束T 太局限了。当然,我的函数不适用于每种类型,但我觉得“强制”它不是类型提示的工作。特别是,我想在任何可以从42 构造的东西上使用这个函数,包括用户定义的类。我会更新问题。
      猜你喜欢
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多