Pytho 中闭包与装饰器详解

闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数就被认为是闭包(closure)。

定义在外部函数内但由内部函数引用或者使用的变量称为自由变量。

总结一下,创建一个闭包必须满足以下几点:

1. 必须有一个内嵌函数

2. 内嵌函数必须引用外部函数中的变量

3. 外部函数的返回值必须是内嵌函数

1.闭包使用示例

先看一个闭包的例子:

In [10]: def func(name):    ...:     def in_func(age):    ...:         print 'name:',name,'age:',age    ...:     return in_func    ...: In [11]: demo = func('feiyu')In [12]: demo(19)name: feiyu age: 19

登录后复制

这里当调用 func 的时候就产生了一个闭包——in_func,并且该闭包持有自由变量——name,因此这也意味着,当函数func的生命周期结束之后,name这个变量依然存在,因为它被闭包引用了,所以不会被回收。

在 python 的函数内,可以直接引用外部变量,但不能改写外部变量,因此如果在闭包中直接改写父函数的变量,就会发生错误。看以下示例:

实现一个计数闭包的例子:

def counter(start=0):count = [start] def incr():count[0] += 1return countreturn incra = counter()print 'a:',aIn [32]: def counter(start=0):    ...:     count = start    ...:     def incr():    ...:         count += 1    ...:         return count    ...:     return incr    ...: In [33]: a = counter()In [35]: a()  #此处会报错UnboundLocalError: local variable 'count' referenced before assignment

登录后复制

应该像下面这样使用:

In [36]: def counter(start=0):    ...:     count = [start]    ...:     def incr():    ...:         count[0] += 1    ...:         return count    ...:     return incr    ...: In [37]: count = counter(5)In [38]: for i in range(10):    ...:     print count(),    ...:     [6] [7] [8] [9] [10] [11] [12] [13] [14] [15]

登录后复制

2.使用闭包的陷阱

In [1]: def create():   ...:     return [lambda x:i*x for i in range(5)]  #推导式生成一个匿名函数的列表   ...: In [2]: create()Out[2]: [>, >, >, >, >]In [4]: for mul in create():   ...:     print mul(2)   ...:     88888

登录后复制

结果是不是很奇怪,这算是闭包使用中的一个陷阱吧!来看看为什么?

在上面的代码当中,函数create返回一个list里面保存了4个函数变量,这4个函数都共同的引用了循环变量i, 也就是说它们共享着同一个变量i,i是会改变的,当函数调用时,循环变量i已经是等于4了,因此4个函数返回的都是8。如果,需要在闭包使用循环变量的值的话,把循环变量作为闭包的默认参数或者是通过偏函数来实现。实现的原理也很简单,就是当把循环变量当参数传入函数时,会申请新的内存。示例代码如下:

In [5]: def create():   ...:         return [lambda x,i=i:i*x for i in range(5)]    ...: In [7]: for mul in create():   ...:     print mul(2)   ...:     02468

登录后复制

3,闭包与装饰

装饰器就是一种的闭包的应用,只不过其传递的是函数:

def addb(func):def wrapper():return '' + func() + ''return wrapperdef addli(func):def wrapper():return '

登录后复制’ + func() + ”return wrapper @addb         # 等同于 demo = addb(addli(demo)) @addli        # 等同于 demo = addli(demo)def demo():return ‘hello world’print demo()    # 执行的是 addb(addku(demo))

在执行时,首先将demo函数传递给addli进行装饰,然后将装饰后的函数传递给addb进行装饰。所以最后返回的结果是:

  • hello world
  • 登录后复制

    4.装饰器中的陷阱

    当你写了一个装饰器作用在某个函数上,这个函数的重要的元信息比如名字、文档字符串、注解和参数签名都会丢失。

    def out_func(func):def wrapper():        func()return wrapper@out_funcdef demo():"""        this is  a demo.    """print 'hello world.'if __name__ == '__main__':    demo()print "__name__:",demo.__name__print "__doc__:",demo.__doc__

    登录后复制

    看结果:

    hello world.__name__: wrapper__doc__: None

    登录后复制

    函数名字和文档字符串都变成了闭包的信息。好在可以使用 functools 库中的 @wraps 装饰器来注解底层包装函数。

    from functools import wrapsdef out_func(func):    @wraps(func)def wrapper():        func()return wrapper

    登录后复制

    自己试试结果吧!

    以上就是Pytho 中闭包与装饰器详解的详细内容,更多请关注【创想鸟】其它相关文章!

    版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

    发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2269282.html

    (0)
    上一篇 2025年2月27日 11:09:01
    下一篇 2025年2月27日 11:09:15

    AD推荐 黄金广告位招租... 更多推荐

    相关推荐

    • python对Mysql数据库进行操作的实例详解

      import MySQLdb#引入mysql模块class ManagerDB:#创建一个类 def __init__(self): self.db=None self.cursor=None self.connit()def connit…

      编程技术 2025年2月27日
      200
    • 总结学习Python的思维导图介绍

      无意间碰到的一个大神整理的python学习思维导图,感觉对初学者理清学习思路大有裨益,非常感谢他的分享。 14 张思维导图 基础知识 数据类型 立即学习“Python免费学习笔记(深入)”; 序列 字符串 列表 & 元组 字典 &a…

      2025年2月27日 编程技术
      100
    • SELECT版FTP的实例详解

      select版ftp:使用select或selectors模块实现并发简单版ftp允许多用户并发上传下载文件   必须使用select or selectors模块支持多并发,禁止使用多线程或多进程 REDMAE 用户登陆1、查看共享目录文…

      2025年2月27日 编程技术
      200
    • python 列表解析

      列表解析,主要用于动态创建列表 本篇主要说一下,lambda、map()、和filter()同列表解析语句之间结合的用法 列表解析的基本语法为:[expr for iter_var in iterable] 这个语句的核心是for循环,他迭…

      编程技术 2025年2月27日
      200
    • Python开发–进程、线程、协程详解

      什么是进程(process)? 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于,程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念…

      2025年2月27日
      200
    • 怎么用Python来读取和处理文件后缀?

      最近在弄一个项目分析的时候,看到有一个后缀为”.sqlite”的数据文件,由于以前没怎么接触过,就想着怎么用python来打开并进行数据分析与处理,于是稍微研究了一下。 SQLite是一款非常流行的关系型数据库,由于它非常轻盈,因此被大量应…

      2025年2月27日
      200
    • 总结Python编码需要注意的地方

      1、map, filter, reduce1) map(func, input_list)将函数应用到输入列表上的每个元素, 如:input_list = [1, 2, 3, 4, 5] def pow_elem(x):    &#8220…

      编程技术 2025年2月27日
      200
    • Python是怎么操作文件和目录的?

      Python操作文件和目录 读写文件比较简单,有一点特别注意就好了 windows下Python默认打开的文件以gbk解码,而一般我们的文件是utf-8编码的,所以如果文本含有中文,就会出现异常或者乱码。此时手动添加encoding=&#8…

      编程技术 2025年2月27日
      200
    • python-函数式编程实例教程

        函数式编程是使用一系列函数去解决问题,按照一般编程思维,面对问题时我们的思考方式是“怎么干”,而函数函数式编程的思考方式是我要“干什么”。 至于函数式编程的特点暂不总结,我们直接拿例子来体会什么是函数式编程。  lambda表达式(匿名…

      编程技术 2025年2月27日
      200
    • 一种解释型语言–python的介绍

      python是一种解释型语言 python 2 或 3的选择:   python 2.7是2的最新版本 也是最后一个版本,更新支持至2020年 将会停止更新,但是现在正在使用或已经开发完成的公司在继续使用python2 ,所以更新的这个过渡…

      编程技术 2025年2月27日
      200

    发表回复

    登录后才能评论