【问题标题】:Why PyCharm reports fake warning to decorated methods? What is the pythonic way of defining decorator for methods?为什么 PyCharm 向修饰方法报告虚假警告?为方法定义装饰器的pythonic方式是什么?
【发布时间】:2021-09-28 13:15:13
【问题描述】:

问题描述

考虑以下场景:

  • 我有一个能够发表演讲的“演讲者”课程。
  • 一些方法,例如“说”,有效地发表演讲。
  • 发表演讲前,我们需要打开麦克风,演讲结束后,我们需要关闭。
  • 为了避免在每一种传递演讲的方法中都这样做,我创建了一个装饰器来打开和关闭麦克风。

这是一个虚构的例子。我真正的代码是关于连接和断开数据库。

代码:

def use_mic(method):
    def wrapper(self, *args, **kwargs):  # [3]
        self.turn_on_mic()  # [2] Method "turn_on_mic" is called, it is not a method of "str"
        method(self, *args, **kwargs)
        self.turn_off_mic()  # [2]

    return wrapper


class Speaker:
    def __init__(self, name):
        self.name = name
        self.mic_on = False

    @use_mic
    def speak(self, message):
        print("[%s speaks] %s" % (self.name, message))

    def turn_on_mic(self):
        print("Turn on microphone")
        self.mic_on = True

    def turn_off_mic(self):
        print("Turn off microphone")
        self.mic_on = False

    def greet(self):
        self.speak('Good morning my neighbours')  # [1] Lint warning here, because [2]


john = Speaker('John')
john.greet()

代码运行正常,但 PyCharm 报告以下 lint 警告:

PyCharm 显然将 [1] 处传递的 str 参数视为 [3] 处的第一个参数“self”,并根据 [2] 警告“没有此类属性”。但是“Python 在使用 . 或 self. 调用时将实例作为方法的第一个参数传递”是常识。

我的问题

  1. 为什么 PyCharm 会误解代码?
  2. 是 PyCharm 默认 lint 工具的 bug,还是我写了非 Python 代码?
  3. 编写此类代码的 Python 方式是什么?
  4. 当我将 [3] 更改为以下代码时,警告消失了,但它是 python 的方式吗?

代码:

def wrapper(*args, **kwargs):  # [2]
    self = args[0]

我正在使用 PyCharm 2021.1.3(社区版)和 Python 3.7.5

【问题讨论】:

  • 这不仅仅是警告,这是错误而且我认为你甚至不能运行该代码,因为wrapper 至少需要一个参数self,所以@ 987654327@ 将是空的,因为 self.speak('Good morning my neighbours')method(*args, **kwargs) 将抛出错误,指出位置 message 参数丢失,因为它已被用作包装器的 self,但 def speak(self, message) 期望它。
  • “代码运行正常”——不,不,它没有。我在 Python 3.9 上运行它,我得到“TypeError: speak() missing 1 required positional argument: 'message'”。你需要method(self, *args, **kwargs) 才能工作。
  • @ThePyGuy 对不起,我弄错了,调用方法时添加“self”
  • @AKX 对不起,我弄错了,调用方法的时候加上“self”
  • 无论你的代码是否是“pythonic”,这看起来像是 PyCharm 中的一个错误。您是否尝试向 JetBrains 报告此问题?至于为什么,没有考虑到错误。

标签: python pycharm decorator lint


【解决方案1】:

老实说,我会为这类事情使用上下文管理器。使用 contextmanager 装饰器(PyCharm 也很好地支持它)很容易实现它们。

from contextlib import contextmanager


class Speaker:
    def __init__(self, name):
        self.name = name
        self.mic_on = False

    @contextmanager
    def using_mic(self):
        self.turn_on_mic()
        try:
            yield
        finally:
            self.turn_off_mic()

    def speak(self, message):
        with self.using_mic():
            print("[%s speaks] %s" % (self.name, message))

    def turn_on_mic(self):
        print("Turn on microphone")
        self.mic_on = True

    def turn_off_mic(self):
        print("Turn off microphone")
        self.mic_on = False

    def greet(self):
        self.speak('Good morning my neighbours')


john = Speaker('John')
john.greet()

【讨论】:

    猜你喜欢
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 2015-12-06
    • 1970-01-01
    • 1970-01-01
    • 2010-12-31
    • 1970-01-01
    相关资源
    最近更新 更多