Python 装饰器

按照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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,...
    chen_000阅读 1,432评论 0 3
  • Python装饰器的高级用法(翻译) 原文地址https://www.codementor.io/python/t...
    城南道阅读 4,885评论 1 22
  • 一. 有时候我们会有这样需求: 在原有的逻辑前后添加一段逻辑 如: 在增/删/改操作之前检查用户是否登录、某个操...
    元亨利贞o阅读 728评论 1 4
  • 装饰器简述 要理解装饰器需要知道Python高阶函数和python闭包,Python高阶函数可以接受函数作为参数,...
    XYZeroing阅读 380评论 0 1
  • 1、写在前面 在学习数据库的时候有很多疑问,期间整理了一下内容,在此记录以供后期学习 2、博客列表 001--Or...
    糖纸疯了阅读 480评论 0 0

友情链接更多精彩内容