问题描述
mypy 将 @classmethod
的绑定语义融入其中(实际上从查看源代码我相信它是为 builtins.classmethod
硬编码的)所以这有效:
from __future__ import annotations
from typing import Any
class Foo:
def __init__(self,x: Any) -> None:
self.x = x
@classmethod
def create(cls,x: Any) -> Foo:
return cls(x)
if __name__ == '__main__':
foo = Foo.create(1)
print(foo)
$ mypy a0.py
Success: no issues found in 1 source file
但是说,出于正当理由,我有一个装饰器,它在第一个参数上具有类似 classmethod
的绑定行为(期望它是一个类)。举一个近似 classmethod
本身的简单例子:
class myclassmethod:
def __init__(self,func):
self.func = func
def __get__(self,obj,cls):
return partial(self.func,cls)
class Foo:
def __init__(self,x: Any) -> None:
self.x = x
@myclassmethod
def create(cls,x: Any) -> Foo:
return cls(x)
不出所料,这不会结账; mypy 假定第一个参数绑定到一个 Foo
实例,并且在 cls(x)
的调用站点出错:
$ mypy a1.py
a1.py:20: error: "Foo" not callable
如果我尝试明确地给“cls”一个类型与实例方法的默认 bind_self
行为相矛盾:
class Foo:
def __init__(self,x: Any) -> None:
self.x = x
@myclassmethod
def create(cls: Type[Foo],x: Any) -> Foo:
return cls(x)
$ mypy a2.py
a2.py:19: error: The erased type of self "Type[a2.Foo]" is not a supertype of its class "a2.Foo"
我发现的唯一解决方法是不在签名中声明 cls
的类型,而是在调用站点进行转换:
class Foo:
def __init__(self,x: Any) -> Foo:
return cast(Type[Foo],cls)(x)
就类型检查而言,这通过了,但有点不方便且容易出错,因为这必须由 @myclassmethod
的任何用户完成。
我看到 mypy 的 is_classmethod
有一个 bind_self
参数,但这实际上仅适用于使用 builtins.classmethod
修饰的函数的特定情况。子类化 classmethod
也无济于事(我猜 mypy 保守地假设 classmethod
的子类可能具有任意行为)。
我只是想知道是否有一种方法可以在不深入研究 mypy 内部结构的情况下显式覆盖作为装饰器参数的函数的自绑定行为。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)