用参数包装装饰器

Wrapping a decorator, with arguments

我正在尝试用一个在调用 marshal_with 之前执行某些操作的装饰器替换 flask-restful 中的 marshal_with 装饰器。我的方法是尝试实现一个包装 marshal_with.

的新装饰器

我的代码如下:

from flask.ext.restful import marshal_with as restful_marshal_with

def marshal_with(fields, envelope=None):
    def wrapper(f):
        print("Do something with fields and envelope")

        @wraps(f)
        def inner(*args, **kwargs):
            restful_marshal_with(f(*args, **kwargs))
        return inner
    return wrapper

不幸的是,这似乎破坏了一切......没有错误消息,但我的 API returns 一个不应该的空响应。关于我做错了什么的任何见解?

我不知道marshal_with的细节,但完全可以在一个函数上使用多个装饰器。例如:

def decorator_one(func):
    def inner(*args, **kwargs):
        print("I'm decorator one")
        func(*args, **kwargs)
    return inner

def decorator_two(text):
    def wrapper(func):
        def inner(*args, **kwargs):
            print(text)
            func(*args, **kwargs)
        return inner
    return wrapper

@decorator_one
@decorator_two("I'm decorator two")
def some_function(a, b):
    print(a, b, a+b)


some_function(4, 7)

给出的输出是:

I'm decorator one
I'm decorator two
4 7 11

您可以通过在每个 inner 函数调用后添加打印语句来修改这个小脚本,以查看每个装饰器之间的确切流程控制。

我在这里做错了几件事,首先,未能如 jonrsharpe 指出的那样 return restful_marshal_with 的输出,其次,未能理解编写为class 而不是函数,以及如何正确地将值传递给它。正确的代码最终是:

def marshal_with(fields, envelope=None):
    def wrapper(f):
        print("Do something with fields and envelope")

        @wraps(f)
        def inner(*args, **kwargs):
            rmw = restful_marshal_with(fields, envelope)
            return rmw(f)(*args, **kwargs)
        return inner
    return wrapper

如您所见,除了不 returning rmw() 之外,我还需要在调用它之前正确初始化 request_marshal_with class。最后,重要的是要记住装饰器 return 函数,因此原始函数的参数应该传递给 rmw(f) 的 return 值,因此语句 return rmw(f)(*args, **kwargs)。如果您看一下 flask_restful.marshal_with 代码 here.

,这可能会更明显