欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Python]从装饰器说开去

程序员文章站 2022-06-14 17:35:21
...
def deco(func):
    print "deco"
    return func
@deco
def foo():
    return "hello"
#main
if __name__=="__main__":
    print foo()

装饰器理解起来就是
def deco(func):
    print "deco"
    return func

def foo():
    return "hello"
#main
if __name__=="__main__":
    fun = deco(foo)
    print fun()

但是装饰器有个重要的特性就是在装饰的时候会调用一次
def deco(func):
    print "deco"
    return func
@deco
def foo():
    return "hello"
#main
if __name__=="__main__":
    pass

理解带参数的装饰器
def deco(**kw):
    print kw
    def _deco(func):
        return func
    return _deco
@deco(key="123")
def foo():
    return "hello"
#main
if __name__=="__main__":
    print foo()

理解起来就是
def deco(**kw):
    print kw
    def _deco(func):
        return func
    return _deco
def foo():
    return "hello"
#main
if __name__=="__main__":
    #print deco(key='123')(foo)()
    fun = deco(key='123')(foo)
    print fun()

利用装饰器在装饰时会调用一次,我们可以利用它在程序真正开始执行之前注册函数,以便方便的在需要的时候调用,实现逻辑解耦,举个栗子!
mapper={}

def deco(**kw):
    key = kw['key']
    def _deco(func):
        #如没有注册到mapper中就把该函数注册进mapper
        if key not in mapper:
            mapper[key] = func
        return func
    return _deco

@deco(key='get')
def foo1():
    return "call get"

@deco(key='post')
def foo2():
    return "call post"
    
#main
if __name__=="__main__":
    key = 'get'
    #查找key=get的函数
    call = mapper[key]
    #调用这个函数
    print call()

这样就形成了一个类似框架的东西,仔细观察的话,很像springMVC或者bottle,下一章节,我们就来用装饰器来封装一下python的web处理,服务器采用tornado,打算实现的最终目标如下:
@Router.route(url=r"hello/([a-z]+)",method=Router._GET|Router._POST)
def test(self,req,who):
    #http://localhost:8888/hello/billy
    return "Hi,"+who
    
@Router.route(url=r"greetings/([a-z]+)",method=Router._GET)
def test2(self,req,who):
    #http://localhost:8888/greetings/rowland
    raise Exception("error")

@Router.route(url=r"book/([a-z]+)/(\d+)",method=Router._GET|Router._POST)
def test3(self,req,categories,bookid):
    #http://localhost:8888/book/medicine/49875
    return "You are looking for a "+categories+" book\n"+"book No. " + bookid
    
@Router.route(url=r"json",method=Router._POST)
def test4(self,req):
    #http://localhost:8888/json
    #print req.request.body
    who=req.json_args.get("who","default")
    age=req.json_args.get("age",0)
    person={}
    person['who']=who
    person['age']=int(age)
    return person