python 中对redis 操作采用装饰器进行处理,怎么做

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 中对redis 操作采用装饰器进行处理,怎么做相关的知识,希望对你有一定的参考价值。

参考技术A redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。importredis导入redis模块,通过python操作redis也

对python中的参数进行操作的嵌套函数装饰器

【中文标题】对python中的参数进行操作的嵌套函数装饰器【英文标题】:Nested function decorators that operate on arguments in python 【发布时间】:2011-12-04 03:03:12 【问题描述】:

我正在编写一个函数装饰器,它将对函数的第一个参数进行转换。如果我只装饰我的功能一次,它工作正常,但如果我装饰它们两次,我会得到一个错误。下面是一些演示问题的代码,它是我正在处理的代码的简化版本。我已经排除了进行转换的代码,以免分散注意力

from inspect import getargspec
from functools import wraps

def dec(id):
    def _dec(fn):
        @wraps(fn)
        def __dec(*args, **kwargs):
            if len(args):
                return fn(args[0], *args[1:], **kwargs)
            else:
                first_arg = getargspec(fn).args[0]
                new_kwargs = kwargs.copy()
                del new_kwargs[first_arg]
                return fn(kwargs[first_arg], **new_kwargs)
        return __dec
    return _dec

@dec(1)
def functionWithOneDecorator(a, b, c):
    print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)

@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
    print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)

functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)

functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)

当我运行上面的代码时,我得到以下输出:

functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
IndexError: list index out of range

这是因为当第二个装饰器检查它正在装饰的函数以查找参数名称时,它失败了,因为它正在装饰一个装饰器并且只需要 *args 和 **kwargs。

我可以想出解决问题的方法,这些方法可以在上面的代码中使用,但如果一个函数用我的装饰器和第 3 方的另一个装饰器装饰,它仍然会中断。有没有解决这个问题的通用方法?还是有更好的方法来达到同样的效果?

更新:感谢@Hernan 指出decorator module。正好解决了这个问题。现在我的代码如下所示:

from decorator import decorator

def dec(id):
    @decorator
    def _dec(fn, *args, **kwargs):
        return fn(args[0], *args[1:], **kwargs)
    return _dec

@dec(1)
def functionWithOneDecorator(a, b, c):
    print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)

@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
    print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)

functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)

functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)    

更干净,并且有效!

【问题讨论】:

为什么args[0], *args[1:],和*args一样? 你想用这个装饰器解决什么问题?据我所知,它的主要目标似乎是确保第一个给定参数 - 关键字/可选或其他 - 始终作为“第一个”参数传递给包装函数。另外,id 参数对装饰器的预期意义是什么?它没有在任何地方使用。 我想对第一个参数进行转换。在上面提供的代码中,我排除了进行转换的代码,以免分散注意力。 在实际代码中,我希望能够定义许多不同的装饰器,每个装饰器对函数的第一个参数进行不同的转换。我希望能够将这些装饰器中的一个以上应用于给定函数以及可能的其他 3rd 方装饰器。 id 只是用来模拟有许多这样的装饰器 - 如果你喜欢 id 是要应用的转换的 id。 【参考方案1】:

问题在于您的装饰函数的签名不是原始签名(getargspec)。 decorator module 的帮助很好地解释了它,您可以解决您的问题。基本上,您应该使用保留签名的装饰器,以便第二个装饰器看到与第一个相同的签名。

【讨论】:

太棒了,这正是我想要的。

以上是关于python 中对redis 操作采用装饰器进行处理,怎么做的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中对装饰器进行分组

python中对变量的作用域LEGB闭包装饰器基本理解

python 工具函数代码

python 工具函数代码

对python中的参数进行操作的嵌套函数装饰器

python函数作用域+装饰器