【问题标题】:Getting a decorator with args to work with method: self does not exist让带有 args 的装饰器使用方法:self 不存在
【发布时间】:2014-11-24 15:28:51
【问题描述】:

当我尝试在装饰中使用参数装饰方法时,它会给我一个 self 未定义。相反,如果我将 assign val 更改为类变量并使用 MyCls.val 它现在给我 MyCls 未定义!如何装饰我的方法?

def dodecorate(VAL):
    def decorate(func):
        def wrapped(*args,**kwargs):
            res = func(*args,**kwargs)
            if res == VAL:
                res = "one"
            return res
        return wrapped
    return decorate


class MyCls(object):
    def __init__(self):
        self.val = 1

    @dodecorate(VAL = self.val)
    def onefrom1(self, x):
        return x

编辑 上面是我发明的一个抽象来表示原件。这是实际的代码。

def retry_on_invalid_schema(MAX_RETRIES):
    def retrier(func):
        def wrapped(*args, **kwargs):
            tries = 0
            res = None
            while tries < MAX_TRIES:
                try:
                    res = func(*args, **kwargs)
                    assert res.has_key('by')
                    assert res.has_key('id')
                    break
                except AssertionError:
                    res = None
                    time.sleep(2**tries)
                    tries += 1
                    continue
            return res
        return wrapped
    return retrier



class Base(object):

    def __init__(self):

        self.MAX_RETRIES = 3

    @retry_on_invalid_schema(MAX_RETRIES = self.MAX_RETRIES)
    def _get_api_response(self, uri):
        return json.loads(self._get(uri))

    def _get(self, uri):
        return requests.get(uri).text

【问题讨论】:

  • 你能出示你的instances吗?
  • @Yax 我在有机会实例化它之前就收到了错误。
  • 在类定义期间调用装饰器函数时,selfMyCls 都不存在。在这里,您真正想要实现什么?

标签: python oop decorator


【解决方案1】:

如果要在实例方法上使用现有的装饰器函数,请注意可以在__init__ 中重新定义实例方法,直接调用装饰器而不是使用@ 语法:

class MyCls(object):

    def __init__(self):
        self.val = 1
        self.onefrom1 = dodecorate(self.val)(self.onefrom1)

    def onefrom1(self, x):
        return x

使用中:

>>> a = MyCls()
>>> for x in range(3):
    print a.onefrom1(x)


0
one
2

【讨论】:

  • 我实际上将问题抽象为我为这个问题发明的一个更简单的问题。实际的装饰器稍微复杂一些,如果响应不是预期的,它会重试 HTTP 请求。它用于脚本的其他部分,我想在我的类方法中重用它。
  • 对此感到抱歉。那我就贴出实物吧。认为这只会分散人们对无关细节的核心问题的注意力。
  • 也许 mixin 会更适合这个任务?
  • @pad 基于更新,我已经删除了答案的第一部分 - 我认为剩下的就是你想要的。
  • @dizpers 我认为关键是 OP 已经 装饰器,所以想要使用它而不是编写重复的代码。但是,如果您认为 mixin 实现会更好,请写一个新答案
【解决方案2】:

您可以通过实例访问它,而不是尝试将val 传递给装饰器。 self 包含当前实例并传递给装饰器中的包装方法,因此您可以在装饰器中将其作为第一个参数访问。

def decorate(func):
    def wrapped(instance, *args, **kwargs):
        res = func(instance, *args, **kwargs)
        if res == instance.val:
            res = "one"
        return res
    return wrapped


class MyCls(object):
    def __init__(self):
        self.val = 1

    @decorate
    def onefrom1(self, x):
        return x

c = MyCls()
print c.onefrom1(1)
print c.onefrom1(2)

输出

one
2

【讨论】:

  • 谢谢,但我需要一个带参数的装饰器。
猜你喜欢
  • 2011-08-02
  • 2021-11-16
  • 2016-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-28
  • 2020-12-16
  • 2020-07-24
相关资源
最近更新 更多