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'
  • 相关阅读:
    .net获取服务器端路径
    js跳转页面回传值问题处理
    关于服务器文件保存到本地文件的浅谈
    ADO.NET中的五个主要对象
    C# 禁止windows程序重复运行的两种基本方法
    一个更好一点的主线程与子线程之间通信的做法
    Django+Nginx配置过程
    一个简单的模板系统的实现(动态载入DLL)
    我的Notepad++环境配置
    一个去除Aspose.Cells生成的EXCEL2007格式中Evaluation Warning的笨办法
  • 原文地址:https://www.cnblogs.com/dylan-wu/p/6705149.html
Copyright © 2011-2022 走看看