我使用PyCharm 2023.2.3(Community Edition)进行开发。有一个脚本:
from functools import cached_property
from collections.abc import Callable
from typing import TypeVar, Generic, Any, overload, Union
T = TypeVar("T")
class result_property(cached_property, Generic[T]):
def __init__(self, func: Callable[[Any], T]) -> None:
super().__init__(func)
def __set_name__(self, owner: type[Any], name: str) -> None:
super().__set_name__(owner, name)
@overload
def __get__(self, instance: None, owner: Union[type[Any], None] = None) -> 'result_property[T]': ...
@overload
def __get__(self, instance: object, owner: Union[type[Any], None] = None) -> T: ...
def __get__(self, instance, owner=None):
return super().__get__(instance, owner)
def func_str(s: str) -> None:
print(s)
class Foo:
@result_property
def prop_int(self) -> int:
return 1
foo = Foo()
func_str(foo.prop_int) # type error is expected here
字符串
PyCharm类型检查器报告它是正确的。然而,我除了它在最后一行报告一个类型错误。如果我在这个脚本上运行mypy检查,它报告:
tmp.py:38: error: Argument 1 to "func_str" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
型
为什么Pycharm报告它没问题?
有没有可能以某种方式修改PyCharm的脚本,以便在这种情况下也报告类型错误?
2条答案
按热度按时间pcww981p1#
显然,PyCharm在其静态类型检查器中硬编码了名称
cached_property
的逻辑,而不是通过适当的类型推断系统来推断修饰方法的类型。它可以是完全虚假的,只要它名为cached_property
,PyCharm仍然会使用相同的逻辑:字符串
因此,为了让你自己的描述符像
cached_property
一样被处理,你只需将其命名为cached_property
,以便PyCharm进行类型检查:型
这并不理想,但必须这样做,直到PyCharm停止基于硬编码名称硬编码类型逻辑的捷径,并为描述符实现逻辑推断类型。
fae0ux8s2#
我刚刚用PyCharm 2023.2.5检查了一下,没有发现任何错误,即使是在尝试更复杂的类版本时,比如在
result_property
类中增强类型提示以提供PyCharm更多信息:字符串
考虑到PyCharm即使在增强了类型提示之后仍然没有报告类型错误,我认为PyCharm的类型推断系统在处理像您这样的复杂场景时有局限性或行为不同,涉及自定义装饰器和泛型。PyCharm和
mypy
之间的差异并不罕见,特别是在更复杂或细微的类型情况下。所以,你的选择,在这一点上,是:
mypy
或其他静态类型检查器作为开发工作流的一部分。在测试或构建过程中单独运行mypy可以帮助捕获这些类型的错误,即使PyCharm没有。你可以install it in PyCharm。
作为一种(非理想的)解决方法,如果类型检查问题对您的项目很重要,请考虑调整代码结构。有时,简化代码或避免过于复杂的类型构造可以使其与各种类型检查器更兼容。