假设我有一个函数,它可以创建传入类的实例。
def instantiate[T](class_: type[T], a: int, b: str) -> T:
return class_(a, b)
我希望类型检查器能够判断一个类是否适合这个函数,i。 e.如果它的
__init__
签名支持这样的实例。
我想使用
Protocol
class FitForInstantiate(Protocol):
__init__: Callable[[int, str], None]
然后说类
T
必须遵守它。
def instantiate[T: FitForInstantiate](class_: type[T], a: int, b: str) -> T:
return class_(a, b)
然后上课
class A:
def __init__(self, a: int, b: str):
self.a = a
self.b = b
class B:
def __init__(self, a: int, b: int):
self.a = a
self.b = b
typechecker Pyright 将接受
A
作为 instantiate
的参数,但会打印 B
的错误。但如果我随后展开 A
的签名:
class A:
def __init__(self, a: int, b: str, c: list | None = None):
self.a = a
self.b = b
self.c = c or []
它将不再遵守协议。即使它仍然对
instatiate
有用,pyright 也会为它打印一个错误。
有没有一种方法可以使用 Python 类型,以便所有具有合适
__init__
签名的类都将被视为正确的类型?
当您更改
instatiate
的签名时,这是可能的
def instantiate(class_: typing.Callable[[int,str], T], a: int, b: str) -> T:
return class_(a, b)
(也许将 'class_' 重命名为 'constructor' 左右)
现在与
一起使用ainst = instantiate( A, 1, 'xyz' )
binst = instantiate( B, 1, 'xyz' ) # this will trigger a type checker warning
缺点是您没有告诉类型检查器“class_”本身是一个类变量。因此,如果您想在
instantiate
中使用“class_”变量的类似类的方面,类型检查器将不允许。
好处是你也可以用它来匹配参数类型。可以作为总计(使用 ParamSpec),也可以单独使用类型变量。