如何在Python中创建自己的“参数化”类型(比如`Optional[T]`)?

2024-10-03 06:22:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在Python中创建自己的参数化类型,用于类型提示:

class MaybeWrapped:
    # magic goes here

T = TypeVar('T')

assert MaybeWrapped[T] == Union[T, Tuple[T]]

别管这个做作的例子;我如何实现这一点呢?我查看了Union和Optional的源代码,但它看起来像是一些我希望避免的低级黑客攻击。在

文档中唯一的建议来自example re-implementation of ^{} that inherits from Generic。但是这个例子更多的是关于__getitem__方法,而不是类本身。在


Tags: 文档类型参数here源代码magicassertoptional
2条回答

如果您只是想创建泛型类或函数,请看一下documentation on mypy-lang.org about generic types它相当全面,比标准库类型文档更详细。在

如果您正在尝试实现您的特定示例,有必要指出type aliases work with typevars您可以简单地执行以下操作:

from typing import Union, TypeVar, Tuple

T = TypeVar('T')

MaybeWrapped = Union[T, Tuple[T]]

def foo(x: int) -> MaybeWrapped[str]:
    if x % 2 == 0:
        return "hi"
    else:
        return ("bye",)

# When running mypy, the output of this line is:
# test.py:13: error: Revealed type is 'Union[builtins.str, Tuple[builtins.str]]'
reveal_type(foo(3))

但是,如果您试图用真正新的语义构造泛型类型,那么您很可能会走运。你剩下的选择是:

  1. 构造某种定制类/元类的东西,pep484兼容的类型检查器可以理解并使用它。在
  2. 以某种方式修改您正在使用的类型检查器(例如,mypy有一个实验性的“插件”系统)
  3. 请求修改pep484以包含新的自定义类型(您可以通过在typing module repo中打开一个问题来实现)。在

正是__getitem__方法实现了所有的魔法。在

这是用[]方括号订阅一个名称时调用的方法。在

因此,您需要在类的类中使用一个__getitem__方法,即它的元类,它将获得括号内的任何内容作为参数。该方法负责动态创建(或检索缓存副本)要生成的任何内容,并将其返回。在

我只是不太可能想象您希望如何进行类型暗示,因为类型库似乎涵盖了所有合理的情况(我想不出它们还没有涵盖的示例)。但是让我们假设您希望一个类返回其自身的副本,但是参数anotate作为它的type_属性:

class MyMeta(type):
    def __getitem__(cls, key):
        new_cls = types.new_class(f"{cls.__name__}_{key.__name__}", (cls,), {}, lambda ns: ns.__setitem__("type", key))
        return new_cls

class Base(metaclass=MyMeta): pass

在交互式模式下尝试时,您可以:

^{pr2}$

相关问题 更多 >