我正在尝试用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
部分是什么意思/做什么?
答案 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的定义,你会发现普通装饰器定义有一个额外级别的嵌套函数 - 外层定义并返回装饰器本身。