【问题标题】:How to statically get TypeVar parameters from a Generic for use in static type checking?如何从 Generic 静态获取 TypeVar 参数以用于静态类型检查?
【发布时间】:2020-10-02 20:36:36
【问题描述】:

我有一个继承自typing.Generic 的类,并传入一个TypeVar 作为参数。

稍后在代码中,我想:

  1. 静态(不是在运行时)从类中获取TypeVar 参数
  2. 将其别名为另一个类型变量
  3. 使用该别名键入提示函数的return

在 Python 中有什么方法可以实现这一点吗?

我唯一缺少的是第 1 步,如何从类型变量中获取类型参数


我的用例

from abc import ABC, abstractmethod
from typing import TypeVar, Generic


TFloat = TypeVar("TFloat", bound=float)


class BaseDataClass(Generic[TFloat], ABC):

    @property
    @abstractmethod
    def data(self) -> TFloat:
        """Get data."""


class ChildDataClass(BaseDataClass[int]):

    @property
    def data(self) -> int:
        return 1

然后我将BaseDataClassChildDataClass 导入另一个模块。

在第二个模块中,有没有办法从BaseDataClass 静态获取TFloat 参数,或者从ChildDataClass 获取int 参数,并在mypy 中使用它?

仅供参考:我使用的是 Python 3.8.2。

【问题讨论】:

    标签: python generics mypy static-typing python-typing


    【解决方案1】:

    没有办法“取出”类型变量。您不应该将类型变量视为可以以某种方式提取的一大块数据。相反,请将其视为定义的一部分。

    我认为根据您的问题,您真正追求的是一种编写函数的方法,该函数接受一些 BaseDataClass[T](或这种类型的子类)并返回 T 的任何内容。

    如果是这样,请创建一个匹配您想要接受的任何定义的函数。但是不要指定内部类型必须是特定的,而是使用泛型来捕获它。

    在这种情况下,我们选择匹配 BaseDataClass[T] 类型的任何东西,我们保持 T 泛型。我们的返回类型将是 T 碰巧匹配的任何内容。

    from typing import TypeVar
    from other_module import BaseDataClass, ChildDataClass
    
    T = TypeVar('T', bound=float)
    
    def extract(wrapper: BaseDataClass[T]) -> T:
        return wrapper.data
    
    
    # BaseDataClass[FloatSubclass] exactly matches against BaseDataClass[T],
    # and so T will be FloatSubclass in 'extract(x)' call.
    
    class FloatSubclass(float): pass
    x: BaseDataClass[FloatSubclass]
    reveal_type(extract(x))  # Mypy displays "FloatSubclass"
    
    
    # ChildDataClass doesn't exactly match BaseDataClass[T], but the child
    # class *is* a subtype of BaseDataClass[int], which does match.
    
    x: ChildDataClass
    reveal_type(extract(x))  # Mypy displays "int"
    

    有关更多详细信息和示例,请参阅mypy docs on generics

    【讨论】:

    • 谢谢@Michael0x2a!我对Generic 的预期用法有误解,这让我明白了。我能够使用上述extract 函数的变体来完成我所需要的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2022-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2023-02-23
    相关资源
    最近更新 更多