2012-01-11 65 views
2

我想在Python中編寫一個簡單(輕量級)的RESTful服務器。我曾經碰到過下面的代碼從Google有人可以解釋這個Python代碼嗎? (可能使用裝飾器)

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使用的語法。這似乎是一個構造函數和函數裝飾的AA怪異組合 - 但是,我所遇到的最新裝飾的各種用途通常是這樣寫的:

def foo(): 
    pass 

def foobar(): 
    pass 

@foo 
@pass 
def some_other_func(): 
    pass 

是什麼代碼意味着/做的@mimerender節?

回答

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

對。整個故事可以在這裏找到:http://stackoverflow.com/questions/739654/understanding-python-decorators – 2012-01-11 11:12:49

+0

@filmor:你不是指GET = mimerender(GET)? - (用你的foo例子) – 2012-01-11 11:26:24

+0

不,我不知道。這就是它的重點。正如其他人回答的,mimerender是一個函數,它返回一個裝飾器。所以表達式'mimerender(...)'(其中'...'是上面給出的參數)*是裝飾器,這意味着它不過是一個函數,它接受另一個函數並且(最好)返回一個函數。所以,如果你熟悉數學符號,它就像'mimerender:params - >(func - > func)'。 – filmor 2012-01-11 11:34:55

1

這裏發生的事情是mimerender是獲得裝飾:

@mimerender 
def GET(self, name): 

但也有一些是需要ARGS傳遞到mimerender,所以他們在那裏完成。

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} 
    """ 
1

調用時mimerender將構建並返回使用所提供的參數的裝飾功能。返回的裝飾器函數然後用於裝飾GET方法。

0

你可能被間距誤導了裝飾的。想象一下,它看起來像這樣:

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

這會使它更清晰嗎?

爲了解釋,這有什麼好做的一個構造函數。相反,這裏做的是mimereader是一個返回裝飾器的函數,而不是實際的裝飾器。該函數接受一系列參數,然後將其「烘烤」到裝飾器本身。如果你看一下mimereader的定義,你會發現對普通的裝飾器定義有一個額外級別的嵌套函數 - 外層定義並返回裝飾器本身。

相關問題