【问题标题】:Why are there warnings in these decorated methods?为什么这些装饰方法中有警告?
【发布时间】:2020-10-31 08:43:37
【问题描述】:

我是带有装饰器的字符串,我的第一个用途是包装一个 HTTP 调用以解决失败的连接。工作代码如下:

import requests

class Gotify:
    def __init__(self):
        self.url = "https://postman-echo.com/status/200"

    def ensure_safe_call(caller):
        def wrapper(*args, **kwargs):
            try:
                r = caller(*args, **kwargs)
                r.raise_for_status()
            except Exception as e:
                try:
                    print(f"cannot reach gotify: {e}: {r.text}")
                except NameError:
                    print(f"cannot reach gotify: {e} (the response r does not exist)")
            else:
                print("OK notified gotify of result change")

        return wrapper

    @ensure_safe_call
    def send(self, title, message):
        return requests.get(self.url)

Gotify().send("hello", "world")

这个正确显示OK notified gotify of result change

在 PyCharm 中编辑此内容时,我收到两个我不理解的警告:

在我的装饰器上下文中它们是什么意思(当我不使用装饰器时没有)

【问题讨论】:

标签: python python-3.x pycharm python-decorators


【解决方案1】:
class Gotify:
    def __init__(self):
        self.url = "https://postman-echo.com/status/200"

    def ensure_safe_call(caller):

因为ensure_safe_call 是一个类方法,所以第一个参数(在您的情况下为caller)实际上是self 参数,即类对象的实例--Gotify

因此,有关 Gotify 对象不可调用的警告消息(它不可调用,因为您尚未在 Gotify 类中覆盖 __call__ 类方法)

Function ensure_safe_call lacks a positional argument -- 这是因为ensure_safe_call 只接受self 参数,并且没有指定任何实际的输入参数(回想一下caller == self 的定义方式)。因此,您的装饰器 ensure_safe_call 不能包装任何东西,因为它不接受任何位置参数。

你需要定义一个位置参数

    def ensure_safe_call(self, caller):
        ...

【讨论】:

  • 当您说“无法包装任何东西”时,您的意思是代码错误?我很惊讶,因为它的行为正确(对于https://postman-echo.com/status/200https://postman-echo.com/status/400,它涵盖了这两种情况(printraise))
  • “不能包装任何东西”是指您不能使用该功能来装饰另一个功能。您装饰的函数作为位置参数传递给装饰器函数--ensure_safe_call 是一个类函数,因此隐式传递给它的 very first 参数是对象的实例(通常称为“ self")——在你的情况下,它被称为caller。您需要向ensure_safe_call 添加另一个参数,第二个参数将是装饰的函数。 def ensure_safe_call(self, caller):
  • 感谢您的解释。我尝试了您的解决方案,i) 警告消失了,但 ii) 代码不再起作用:) (TypeError: ensure_safe_call() missing 1 required positional argument: 'caller')。不过,我在示例中的代码确实有效。所以我很困惑——尤其是你清楚地说明了一点。
  • 好吧,为了避免这个问题,你应该让ensure_afe_call 成为一个 tatic 函数(把它带到课堂之外)。它的编写方式 是一个静态函数——将它移出你的类并保留签名 ensure_safe_call(caller) 会给你你正在寻找的结果。根据我的经验,我以前从未将装饰器视为类函数。我只将它们视为静态函数
猜你喜欢
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-10
  • 1970-01-01
  • 2012-04-17
相关资源
最近更新 更多