美文网首页
Python 装饰器

Python 装饰器

作者: 空即是色即是色即是空 | 来源:发表于2017-11-17 20:25 被阅读6次

    按照python官方文档,函数定义可以被一个或者多个decorator包起来,解释如下:

    @f1(arg)
    @f2
    def func(): pass
    

    等同于

    def func(): pass
    func = f1(arg)(f2(func))
    

    而且:Decorator expressions are evaluated when the function is defined, in the scope that contains the function definition


    Example 1. 无参数装饰器

    def hello(fn):
        def wrapper():
            print "hello, %s" % fn.__name__
            fn()
            print "goodby, %s" % fn.__name__
        return wrapper
     
    @hello
    def foo():
        print "i am foo"
    

    解释

    • 编译器做如下转换:
    @hello
    def foo     # ===> hello(foo)
    
    • foo = hello(foo) = wrapper
    • foo此时仅仅是一个函数,没有被调用,foo()才会调用

    这种装饰器,仅仅将在已有函数的基础之上,附加额外的装饰功能。
    到底什么时候调用,由使用者决定


    Example 2. 带参数装饰器

    def hello(dummy=""):
        def wrapper(fn):
            print "hello, %s" % fn.__name__
            fn()
            print "goodby, %s" % fn.__name__
        return wrapper
     
    @hello("")
    def foo():
        print "i am foo"
    

    解释

    • 编译器做如下转换:
    @hello("")
    def foo     # ===> hello("")(foo)
    
    • foo = hello("")(foo)
    • hello("") = wrapper
    • foo = wrapper(foo)
    • 此时编译器已经执行wrapper函数
    • 由于wrapper没有返回值,foo=None

    这种装饰器就不一样了,函数定义期间就被赋予执行的行为
    设想:这可以被用来做某些初始化动作

    从上面的例子分析可以看到,被decorator的函数其实已经是另外一个函数了,对于最前面那个hello.py的例子来说,如果你查询一下foo.__name__的话,你会发现其输出的是“wrapper”,而不是我们期望的“foo”,这会给我们的程序埋一些坑。所以,Python的functool包中提供了一个叫wrap的decorator来消除这样的副作用

    from functools import wraps
    def hello(fn):
        @wraps(fn)
        def wrapper():
            print "hello, %s" % fn.__name__
            fn()
            print "goodby, %s" % fn.__name__
        return wrapper
     
    @hello
    def foo():
        '''foo help doc'''
        print "i am foo"
        pass
     
    foo()
    print foo.__name__ #输出 foo
    print foo.__doc__  #输出 foo help doc
    

    应用1. 给函数调用做缓存

    from functools import wraps
    def memo(fn):
        cache = {}
        miss = object()
     
        @wraps(fn)
        def wrapper(*args):
            result = cache.get(args, miss)
            if result is miss:
                result = fn(*args)
                cache[args] = result
            return result
     
        return wrapper
     
    @memo
    def fib(n):
        if n < 2:
            return n
        return fib(n - 1) + fib(n - 2)
    

    应用2. 注册回调函数

    class MyApp():
        def __init__(self):
            self.func_map = {}
     
        def register(self, name):
            def func_wrapper(func):
                self.func_map[name] = func
                return func
            return func_wrapper
     
        def call_method(self, name=None):
            func = self.func_map.get(name, None)
            if func is None:
                raise Exception("No function registered against - " + str(name))
            return func()
     
    app = MyApp()
     
    @app.register('/')
    def main_page_func():
        return "This is the main page."
     
    @app.register('/next_page')
    def next_page_func():
        return "This is the next page."
     
    print app.call_method('/')
    print app.call_method('/next_page')
    

    参考自:coolshell

    相关文章

      网友评论

          本文标题:Python 装饰器

          本文链接:https://www.haomeiwen.com/subject/zmhjvxtx.html