我很好奇是否有可能让Mypy了解类中的某些方法 cls
参数而不是 self
参数。我想到的具体用例是在键入sqlalchemy hybrid_property
's .expression
decorator,但更简单的示例将尝试实现自定义/非构建 - 在 classMethod
的版本中。
将显式类型注释应用于 cls
不起作用,例如
from typing import Type
class Example:
@my_custom_classmethod
def foo(cls: Type["Example"]) -> str:
return "doesn't work"
mypy抱怨删除的自我“ type [ackemens]”不是其类“示例” ,我猜这通常是有道理的,但是在这里没有意义:/
我设法提出的最好的解决方案就是##type:imagore 方法的签名:
class Example:
@my_custom_classmethod
def foo(cls: Type["Example"]) -> str: # type: ignore
return "this actually kind of does work!"
实际上,这实际上确实可以正常工作,因为 cls
在方法的主体中具有正确的类型,并且装饰器接收到正确类型的方法,但感觉有些骇人听闻。
I'm curious if it's possible to get mypy to understand that some method in a class takes a cls
argument rather than a self
argument. The concrete use-case I have in mind is typing a sqlalchemy hybrid_property
's .expression
decorator, but a simpler example would be trying to implement a custom/non-built-in version of classmethod
.
Applying an explicit type annotation to cls
doesn't work, e.g.
from typing import Type
class Example:
@my_custom_classmethod
def foo(cls: Type["Example"]) -> str:
return "doesn't work"
Mypy complains that The erased type of self "Type[Example]" is not a supertype of its class "Example"
, which, ok, I guess often makes sense, but it doesn't make sense here :/
The best solution I've managed to come up with so far is to just # type: ignore
the method's signature:
class Example:
@my_custom_classmethod
def foo(cls: Type["Example"]) -> str: # type: ignore
return "this actually kind of does work!"
This actually does seem to basically work, insofar as cls
has the right type in the body of the method and the decorator receives a method of the right type, but it feels a bit hacky.
发布评论
评论(1)
bind_self
是一种检查和分配self
(cls
)类型的方法。它依赖于is_classmethod
node flag(实现在这里)。flag
is_classmethod
在语义分析期间设置在这里。它是通过直接比较装饰器和incears.classmethod
来完成的。因此,您的custom_classmethod
不被视为classMethod
。因此,您无法生产将相当于
ClassMethod
内置的装饰器。但是,您可以使用自定义描述符克服此问题:这在运行时起作用并通过类型检查。描述符很有趣。我假设
python> = 3.10
,最近的足够mypy
:较旧的Python版本可能需要一些更改(至少从typing_extensions
导入),旧的mypy
在完整的描述符支持的情况下可能会遇到麻烦。是的,您可以从ClassMethod
继承。如果您不想要,则必须重新实施__获取__
和__ INIT __
无论如何(以及__ func __
属性,如果您喜欢一致性)。请记住,在3.10及以后的classMethod
还具有包装
属性。这是
bind_self
is a method that checks and assignsself
(cls
) type. It relies onis_classmethod
node flag (implementation here).Flag
is_classmethod
is set during semantic analysis here. It is done by direct comparison of decorator andbuiltins.classmethod
. So yourcustom_classmethod
is not consideredclassmethod
.So you cannot produce decorator that will be equivalent to
classmethod
builtin. However, you can overcome this problem using custom descriptor:This works on runtime and passes type checking. Descriptors are funny. I'm assuming
python >= 3.10
and recent enoughmypy
: older python versions may require some changes (at least imports fromtyping_extensions
), oldmypy
can have troubles with full descriptor support. And yes, you can inherit fromclassmethod
. If you don't want, you'll have to re-implement__get__
and__init__
anyway (and__func__
property if you like consistency). Remember that in 3.10 and laterclassmethod
also haswrapped
property.Here's playground with this code.