在装饰器中使用self是不好的做法吗?

时间:2010-09-02 22:27:01

标签: python decorator

虽然我知道您无法直接在装饰器中引用self,但我想知道通过从args[0]拉出来解决这个问题是不好的做法。我的预感是,但我想确定。

更具体地说,我正在开发一个Web服务的API。大约一半的命令需要传递令牌,稍后可以使用它来撤消它。我想要的是使该标记成为可选参数,如果没有提供,则生成一个。生成令牌需要对服务器进行经过身份验证的调用,该服务器需要来自对象的数据。

虽然我知道我可以做到:

def some_command(self, ..., undo_token = None):
    if undo_token = None:
        undo_token = self.get_undo_token()
    ...
    return fnord

我觉得可能有更好的方法,而不是在十几种方法中使用相同的代码。我的想法是写一个装饰师:

@decorator
def undoable(fn, *args, **kwargs):
    if 'undo_token' not in kwargs:
        kwargs['undo_token'] = args[0].get_undo_token()
    return (fn(*args, **kwargs), kwargs['undo_token'])

所以我可以更干净地写

@undoable
def some_command(self, ...):
    ...
    return foo

@undoable
def some_other_command(self, ...):
    ...
    return bar

我是否因为遇到麻烦而陷入困境?

2 个答案:

答案 0 :(得分:6)

我不明白你为undoable编码的是什么 - 这不是装饰器通常编码的方式,我不知道@decorator来自哪里(有from youforgottotelluswhence import decorator 1}}或者甚至更邪恶的东西?看看为什么我不能忍受使用from构建“人工昵称”而不是使用漂亮的装饰名称? - )。

使用正常的装饰器编码,例如......:

import functools

def undoable(f):
    @functools.wraps(f)
    def wrapper(self, *a, **k):
        tok = k.get('undo_token')
        if tok is None:
            tok = k['undo_token'] = self.get_undo_token()
        return f(self, *a, **k), tok
    return wrapper

命名包装器的第一个强制位置参数self绝对没有问题,并且在使用它时可以大大提高清晰度,而不是使用不太可读的args[0]

答案 1 :(得分:2)

装饰器以通用方式扩展它所装饰的函数的功能。如果装饰者不对该函数或它的args或kwargs做出任何假设,那么它是最通用的形式,并且可以很容易地与许多函数一起使用。

然而,如果你想对传递给函数的内容做些什么,它应该没问题,但它们的适用性是有限的,如果您在装饰器中使用的底层细节发生变化,它们可能会中断。

在上面的装饰器中,如果对象删除方法get_undo_token(),则还需要重新访问装饰器。可以这样做,但记录约束,并将该文档添加到自己的方法文档中。

只有绝对必要时才这样做。它用于创建更通用的装饰器。