有人可以解释这个Python代码吗? (可能使用装饰器)

时间:2012-01-11 11:02:28

标签: python

我正在尝试用Python编写一个简单(轻量级)的RESTful服务器。我从Google发现了以下代码:

import web
import json
from mimerender import mimerender

render_xml = lambda message: '<message>%s</message>'%message
render_json = lambda **args: json.dumps(args)
render_html = lambda message: '<html><body>%s</body></html>'%message
render_txt = lambda message: message

urls = (
    '/(.*)', 'greet'
)
app = web.application(urls, globals())

class greet:
    @mimerender(
        default = 'html',
        html = render_html,
        xml  = render_xml,
        json = render_json,
        txt  = render_txt
    )
    def GET(self, name):
        if not name: 
            name = 'world'
        return {'message': 'Hello, ' + name + '!'}

if __name__ == "__main__":
    app.run()

我不熟悉行@mimerender上使用的语法。这似乎是构造函数和函数装饰器的奇怪组合 - 但是,我迄今遇到的装饰器的所有使用通常都是这样编写的:

def foo():
    pass

def foobar():
    pass

@foo
@pass
def some_other_func():
    pass

代码的@mimerender部分是什么意思/做什么?

4 个答案:

答案 0 :(得分:6)

@expr
def foo(args):
    pass

相当于

def foo(args):
    pass
foo = expr(foo)

expr可以是任何有效的python表达式,所以这里发生的是mimerender(…)返回一个可调用对象(通过构造函数或作为返回可调用对象的函数)。这附近没什么魔力:))

上述电话只是

def GET(self, name):
    if not name: 
        name = 'world'
    return {'message': 'Hello, ' + name + '!'}
GET = mimerender(…)(GET)

答案 1 :(得分:1)

这里发生的事情是mimerender是GET的装饰者:

@mimerender
def GET(self, name):

但是还需要传递给mimerender的args,所以他们就在那里完成了。

如果你想要一些额外的阅读,请从mimerender的文档字符串中填写:

def mimerender(default=None, override_arg_idx=None, override_input_key=None, **renderers):
    """
    Usage:
        @mimerender(default='xml', override_arg_idx=-1, override_input_key='format', , <renderers>)
        GET(self, ...) (or POST, etc.)

    The decorated function must return a dict with the objects necessary to
    render the final result to the user. The selected renderer will be called
    with the map contents as keyword arguments.
    If override_arg_idx isn't None, the wrapped function's positional argument
    at that index will be removed and used instead of the Accept header.
    override_input_key works the same way, but with web.input().

    Example:
    class greet:
        @mimerender.mimerender(
            default = 'xml',
            override_arg_idx = -1,
            override_input_key = 'format',
            xhtml   = xhtml_templates.greet,
            html    = xhtml_templates.greet,
            xml     = xml_templates.greet,
            json    = json_render,
            yaml    = json_render,
            txt     = json_render,
        )
        def GET(self, param):
            message = 'Hello, %s!'%param
            return {'message':message}
    """

答案 2 :(得分:1)

当调用mimerender时,将使用提供的参数构造并返回装饰器函数。然后使用返回的装饰器函数来装饰GET方法。

答案 3 :(得分:0)

你可能被装饰者的间距误导了。想象一下它看起来像这样:

@mimereader(default=html)
def GET(self, name):

这会让它更清楚吗?

要解释一下,这与构造函数无关。相反,这里要做的是mimereader是一个返回装饰器的函数,而不是实际的装饰器。此函数接受一系列参数,然后将其“烘焙”到装饰器本身。如果你看一下mimereader的定义,你会发现普通装饰器定义有一个额外级别的嵌套函数 - 外层定义并返回装饰器本身。