zoukankan      html  css  js  c++  java
  • 【python】装饰器

    来源:廖雪峰

    看了好多次装饰器,发现还是廖老师讲得好,能让我看懂.....

    下面是一段装饰器代码

    @log
    def now():
        print "20161107"

    它的含义等价于

    def now():
        print "20161107"
    
    now = log(now)

    即,log是一个函数,接收一个函数做参数,now变成了log(now)的返回值

    下面,加上一个简单的log函数,只嵌套一层。

    def log(func):
        print 'call %s():' % func.__name__
        return func
    
    @log
    def now():
        print "20161107"
    print "-----"
    now()

    结果

    call now():
    -----
    20161107

    在log函数中打印了被调用函数的名称,但是一共只会运行一次,在定义的时候。之后每次运行now函数结果和不加装饰器相同。

    两层嵌套

    def log(func):
        def wrapper(*args, **kw):
            print 'call %s():' % func.__name__
            return func(*args, **kw)
        return wrapper
    
    @log
    def now():
        print "20161107"
    
    print "-----"
    now()
    now()
    print now.__name__

    结果

    -----
    call now():
    20161107
    call now():
    20161107
    wrapper

    可以看到,在两层嵌套中,可以实现每次运行now函数时都打印函数名。

    在用log装饰后,now=log(now) 也就是wrapper函数,wrapper函数中封存了原本的now函数,采用可变参数,保证wrapper可以接收now函数的变量。wrapper中会先打印函数名,然后返回原本now函数的结果。

    问题是,在打印名称时,now.__name__已经变成了wrapper。需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

    不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下

    import functools
    
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print 'call %s():' % func.__name__
            return func(*args, **kw)
        return wrapper

    三层嵌套,实现装饰器参数

    装饰器也是可以有参数的,比如@log("123")这样

    下面是例子

    def log(*args0, **kw0):
        def decorator(func):
            def wrapper(*args1, **kw1):
                if len(args0) == 0:
                    print "args0 = None"
                else:
                    print args0
                if len(kw0) == 0:
                    print "kw0 = None"
                else:
                    print kw0
                return func(*args1, **kw1)
            return wrapper
        return decorator
    
    
    @log("huhuhuhu")
    def a(x, y):
        print "A"
        return x + y
    
    
    @log()
    def b():
        print "B"
    
    @log("c", t=1, e=2, s=3)
    def c():
        print "C"
    
    A = a(3,2)
    print A
    print "------------"
    b()
    print "------------"
    c()

    结果

    ('huhuhuhu',)
    kw0 = None
    A
    5
    ------------
    args0 = None
    kw0 = None
    B
    ------------
    ('c',)
    {'s': 3, 'e': 2, 't': 1}
    C

    @log("huhuhuhu")的含义为:

    now = log("huhuhuhu")(now)

           = decorator(now)

           = wrapper

    可以看到,通过增加一层嵌套实现了装饰器参数

  • 相关阅读:
    助理需要看的书
    linux 磁盘管理以及维护
    转:工作与创业区别
    《编写可读代码的艺术》---把控制流变得可读
    Visual studio插件 Reshaper--- 常用快捷键
    为啥我喜欢在Windows 7环境下做Unity开发?
    《编写可读代码的艺术》---写出言简意赅的注释
    《编写可读代码的艺术》---该写什么样的注释
    《编写可读代码的艺术》---美观代码
    《编写可读代码的艺术》---不会误解的名字
  • 原文地址:https://www.cnblogs.com/dplearning/p/6044712.html
Copyright © 2011-2022 走看看