zoukankan      html  css  js  c++  java
  • [Python]返回函数,装饰器拾遗

    def lazy_print(*args):
         def pr():
             print(args)
         return pr

    当我们调用lazy_print()时,返回的并不是求和结果,而是求和函数:

    >>> p = lazy_print(1,2,3,4,5)
    >>> p
    <function lazy_print.<locals>.pr at 0x000000000364ED90>

    调用函数p时,才真正计算求和的结果:

    >>> p()
    (1, 2, 3, 4, 5)

    .....

    一个函数可以返回一个计算结果,也可以返回一个函数。

    返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

    装饰器

    首先定义一个装饰器:

    def log(fun):    
        def wrapper():
            print('This is wrapper!')
            return fun()
        return wrapper

    观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

    @log
    def now():
        print('This is now!')

    调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:

    >>> now()
    This is wrapper!
    This is now!

    @log放到now()函数的定义处,相当于执行了语句:

    now = log(now)

    由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

    因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

    >>> now.__name__
    'wrapper'

    因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

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

    import functools
    
    def log(fun):
        @functools.wraps(fun)
        def wrapper():
            print('This is wrapper!')
            return fun()
        return wrapper

    import functools是导入functools模块。模块的概念稍候讲解。现在,只需记住在定义wrapper()的前面加上@functools.wraps(func)即可。

    >>> now.__name__
    'now'
  • 相关阅读:
    cf D. Vessels
    cf C. Hamburgers
    zoj 3758 Singles' Day
    zoj 3777 Problem Arrangement
    zoj 3778 Talented Chef
    hdu 5087 Revenge of LIS II
    zoj 3785 What day is that day?
    zoj 3787 Access System
    判断给定图是否存在合法拓扑排序
    树-堆结构练习——合并果子之哈夫曼树
  • 原文地址:https://www.cnblogs.com/dylan-wu/p/6705149.html
Copyright © 2011-2022 走看看