我想创建一个泛型类型
A[T]
,其行为与
T
完全相同,只不过我可以在运行时告诉我该类型实际上是
A[T]
而不是
T
我尝试过
class A(Generic[T], T):
pass
但是似乎不起作用,正如 mypy 抱怨的那样,例如,
A[str]
的类型为
object
作为一个例子,我希望这样的东西通过类型检查:
def f(s: A[str]):
return re.findall('foo|bar', s)
但仍然能够以某种方式告诉
A[str]
来自
str
在运行时,当我获取该类型的变量或检查函数签名时。
有办法做到这一点吗?
你可以通过从
Generic[T]
继承并使用
__class_getitem__
来实现这一点:
from typing import TypeVar, Generic
import re
T = TypeVar('T')
class A(Generic[T]):
def __class_getitem__(cls, type_):
return type(f'A[{type_}]', (type_,), {})
def f(s: A[str]):
return re.findall('foo|bar', s)
s = A[str]('foobarbaz')
print(f(s)) # ['foo', 'bar']
print(type(s)) # <class '__main__.A[<class 'str'>]'>
print(isinstance(s, str)) # True
解释:
-
__class_getitem__(cls, type_)
: 这个方法在使用方括号语法访问类时被调用,例如A[str]
。它动态创建一个继承自type_
(在本例中为str
)的新类,并将其命名为A[str]
。 -
type(f'A[{type_}]', (type_,), {})
: 这段代码动态创建一个新类。-
f'A[{type_}]'
:设置新类的名称,例如A[str]
。 -
(type_,)
:指定新类的父类。在本例中,它是str
。 -
{}
:一个空字典,用于设置新类的属性。
-
使用这种方法,
A[str]
的行为就像
str
一样,但你仍然可以使用
type(s)
在运行时区分它。
其他方法:
除了上述方法外,你还可以考虑使用:
-
组合而不是继承:
创建一个包装
T
并提供额外运行时信息的类。 -
装饰器:
使用装饰器标记
T
类型的函数或变量。
选择哪种方法取决于你的具体需求和代码库的整体设计。
标签:python,mypy,python-typing From: 78754768