为什么 PyCharm 提示不能与装饰器一起使用?

问题描述 投票:0回答:1

PyCharm 版本:2019.1.2

Python版本:3.7

我正在尝试使用最少的代码来重现问题。这是我的代码片段:

def sql_reader():
    def outer(func):
        def wrapped_function(*args, **kwargs):
            func(*args, **kwargs)
            return [{"a": 1, "b": 2}]

        return wrapped_function

    return outer


@sql_reader()
def function_read():
    return "1"


result = function_read()

for x in result:
    print(x['a'])
print(result)

基本上,我正在做的就是“装饰”一些函数以输出不同的类型。例如,在此代码片段中,被修饰的函数返回 1,即 int。但是,在装饰器中,我更改了行为并返回字典列表

从功能上来说,效果还不错。但看起来我的 IDE 总是抱怨它,这很烦人,如下所示: enter image description here

我可以摆脱这个警告信息吗?

python generics pycharm python-typing
1个回答
0
投票

恕我直言,您使用的是 3 年多前的 PyCharm 版本。我很难找到原因。社区版是免费的,无需 root 权限即可解压并在 Linux 系统上运行。您应该认真考虑升级到最新版本。

顺便说一句,Python 也是如此。您可以通过 Pyenv 安装任何版本(包括最新版本),无需 root 权限。尽管 Python 版本要求可能会受到您正在处理的代码的外部限制,所以这只是一个建议。但对于 IDE,我认为没有理由使用如此过时的版本。


由于我没有使用您的 PyCharm 版本,因此无法重现您的问题。版本 2022.2.3 的代码不存在此类问题。尽管如此,您可以做一些事情来让静态类型检查器(以及您自己)的生活变得更轻松。

当您通过装饰器包装函数时,我always建议的第一件事是使用

functools.wraps
。这保留了许多有关包装函数的有用元数据,甚至将对其的引用存储在包装器的
__wrapped__
属性中。

第二个是正确的类型注释。这应该适用于您编写的任何代码,除非它确实只是一个快速而肮脏的草稿脚本,您只会使用一次然后扔掉。正确的注释尤其是与现代 IDE 结合使用的好处是巨大的。有很多资源对其进行解释,因此我不会在这里详细介绍。

在这种具体情况下,正确的类型提示将消除函数返回类型的歧义,并且应该适用于任何 IDE(无法忍受的错误)。在我的 PyCharm 版本中,包装函数的返回类型被推断为

Any
,因为不存在注释,这可以防止弹出任何像您这样的警告,但也不允许提供任何有用的自动建议。

这是我将如何处理你的代码:(应该与Python兼容

3.7

from functools import wraps
from typing import Any, Callable, Dict, List


AnyFuncT = Callable[..., Any]
ResultsT = List[Dict[str, int]]


def sql_reader() -> Callable[[AnyFuncT], Callable[..., ResultsT]]:
    def outer(func: AnyFuncT) -> Callable[..., ResultsT]:
        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> ResultsT:
            func(*args, **kwargs)
            return [{"a": 1, "b": 2}]
        return wrapper
    return outer


@sql_reader()
def function_read() -> str:
    return "1"

在下面添加

reveal_type(function_read())
并在此文件上调用
mypy
会产生以下结果:

note: Revealed type is "builtins.list[builtins.dict[builtins.str, builtins.int]]"
Success: no issues found in 1 source file

如您所见,至少

mypy
现在可以正确推断我们放置在
function_read
周围的包装函数返回的类型。您的 IDE 应该 也可以正确推断所涉及的类型,但正如我所说,我无法用我的版本验证这一点。

此外,现在 PyCharm 将为您提供所涉及类型上可用方法的自动建议:

results = function_read()
first = results[0]
value = first["a"]

如果我现在开始输入

results.
,PyCharm 会建议诸如
append
extend
等内容,因为它将
result
识别为列表。如果我输入
first.
,它会建议
keys
values
等(推断它是一本字典),如果我输入
value.
,它会给出诸如
imag
real
to_bytes
之类的选项,可用于整数。

更多信息:

typing
模块文档

© www.soinside.com 2019 - 2024. All rights reserved.