Python3(九) 闭包
一. 一切皆对象
函数式编程并没有标准定义,如果代码非常繁琐则考虑使用。
学习闭包的概念,不是python独有的。
其他大多数语言中的函数只是一段可执行的代码,并不是对象。
python中的函数是对象,一切皆对象。可以把函数赋值给变量:
a = 1
a = '2'
a = def
甚至可以把函数当作另外一个函数的参数传递或者当成返回值返回,而C#中要封装成委托。
二.什么是闭包:闭包=函数+函数定义时的环境变量
我们尝试从概念上去理解一下闭包。
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。—— 维基百科
用比较容易懂的人话说,就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。
1.
code1
def curve_pre():
def curve():
pass
curve() #找不到,因为curve()的作用域仅限于curve_pre()的内部
code2
def curve_pre(): def curve():
print('This is a function') pass return curve #函数可以作为结果返回 f = curve_pre() #函数可以赋值 f()#执行函数,不会报错
#This is a function
code3
def curve_pre(): a = 25 #局部变量在curve的外部 def curve(x): #接受抛物线的x值 return a * x * x return curve #返回一个函数 f = curve_pre() print(f(2)) #调用curve()函数 #
code4
a = 10
def f1(x):
return a * x * x
print(f1(2))
#40 #局部变量找不到会去上一级找
code 3 和 code4 对比
def curve_pre(): a = 25 #局部变量在curve的外部 def curve(x): #接受抛物线的x值 return a * x * x return curve #返回一个函数 a = 10 #定义a = 10 f = curve_pre() print(f(2)) #调用curve()函数 #100 #仍然是a = 25的取值,取得是定义时的环境变量,这就是闭包
函数及其外部环境变量所构成的整体叫做闭包
2.环境变量要在函数外部,但不能是全局变量:
a = 25 #a定义为了全局变量 def curve_pre(): def curve(x): #接受抛物线的x值 return a * x * x return curve #返回一个函数 a = 10 f = curve_pre() print(f(2)) #调用curve()函数 #40 #a的值被改变了,因为没有形成闭包
查看:
def curve_pre(): a = 25 #局部变量在curve的外部 def curve(x): #接受抛物线的x值 return a * x * x return curve #返回一个函数 a = 10 f = curve_pre() print(f.__closure__) print(f.__closure__[0].cell_contents)#取出闭包的环境变量 print(f(2)) #调用curve()函数 #(<cell at 0x0031AAF0: int object at 0x0FF93A80>,) #25 #这里是a的值 #
三.一个事例看看闭包
1.闭包的意义:闭包保存的是一个环境,把函数现场保存起来了。
闭包 = 函数 + 函数定义时的环境变量(不能是全局变量)
2. 闭包的经典误区 从外层向内层分析
def f1(): a = 10 def f2(): a = 20 #对a重新赋值局部变量,不会影响到外部 print(a) print(a) # f2() #20 #f1内部调用f2 print(a) # f1() # # #
验证其是不是一个闭包:
1
def f1(): a = 10 def f2(): a = 20 # print(a) #print(a) f2() #print(a) f = f1() #f1是None类型 print(f.__closure__) #报错
(2)加上返回值,仍然不是闭包函数:
def f1(): a = 10 def f2(): a = 20 #a被认为是一个局部变量了,就不认为是个环境变量了 return a return f2 f = f1() print(f.__closure__) #没有__closure__属性 #None
(3)去掉f2()中的赋值后是闭包函数:
def f1(): a = 10 def f2(): #a = 20 #删除a = 20,此时a被python认为是一个局部变量 return a return f2 f = f1() print(f.__closure__) #(<cell at 0x02F5AAF0: int object at 0x0FF93990>,)
原因:环境变量不能当作一个变量去赋值,而是一定要去引用外部。
四.出个题,用闭包解决!
闭包不是必不可少的东西,只是可以使你的代码架构更加合理。
题目:
旅行者,x = 0 为起点,没走一步加1,计算出旅行者当前所处的位置。
关键点:每次调用时需要调用上次的结果
1.先用非闭包解决一下
origin = 0 def go(step): global origin #将origin变成全局变量 new_pos = origin + step origin = new_pos #等号左边的origin被python认识是局部变量 return origin print(go(2)) print(go(3)) print(go(6)) # # #
2.再用闭包解决一下
origin = 0 def factory(pos): #工厂模式 def go(step): nonlocal pos #强制声明不是局部变量 new_pos = pos + step pos = new_pos return new_pos return go tourist = factory(origin) print(tourist(2))
print(origin) print(tourist(3)) print(tourist(6)) #
# # #
并没有改变全局变量origin的值
五.小谈函数式编程
- python和Javascript都会使用闭包。
- 闭包特点:在一个函数外部间接调用函数内部的变量,从模块级别间接调用局部变量。
- 极易造成内存泄漏。
闭包的概念
Python3(九) 闭包的更多相关文章
- Python3基础 闭包 简单示例
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
- Swift5 语言指南(九) 闭包
闭包是自包含的功能块,可以在代码中传递和使用.Swift中的闭包类似于C和Objective-C中的块以及其他编程语言中的lambdas. 闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用 ...
- python3 之 闭包实例解析
一.实例1: def make_power(y): def fn(x): return x**y return fn pow3 = make_power(3) pow2 = make_power(2) ...
- python学习之路 五:函数式编程
本节重点 掌握函数的作用.语法 掌握作用域.全局变量与局部变量知识 掌握函数名称空间.闭包 一.函数编程基础知识 1.基本定义 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数 ...
- Web前端经典面试试题(一)
本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案.眼看新的一年马上就要开始了,相信很多的前端开发者会有一些跳槽的悸动,通过对本篇知识的整理以及经验的总结,希望能帮到更多的前端 ...
- python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法
python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...
- python3.4学习笔记(九) Python GUI桌面应用开发工具选择
python3.4学习笔记(九) Python GUI桌面应用开发工具选择 Python GUI开发工具选择 - WEB开发者http://www.admin10000.com/document/96 ...
- python3 练习题100例 (九)
题目九:题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?程序分析:兔子的规律为数列1,1,2,3,5 ...
- python3 练习题100例 (十九)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """练习十九:计算1-2+3...+99中除了88以外所有数的和" ...
随机推荐
- 迭代器使用过程中为什么抛出ConcurrentModificationException
出现的场景:在迭代器对集合进行遍历的同时,集合本身进行变更操作(add(), remove(), set()). 当正常调用时: import java.util.ArrayList; import ...
- IO流之处理流用法总结
处理流之一:缓冲流1.为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区. 2.缓冲流要“套接”在相应 ...
- Spring中的beanPostProcess的作用
BeanPostProcessor是Spring框架中非常重要的bean之一.贯穿在Spring容器中bean的初始化的整个过程. Spring中的beanpostProcess体系结构如下: 可以看 ...
- Spring(一)开篇
目录 1.Spring 介绍 2.Spring 框架的演变 3.Spring 整体架构 Core Container Data Access/Integration Web AOP Test 最后 1 ...
- Java 设置Word页边距、页面大小、页面方向、页面边框
本文将通过Java示例介绍如何设置Word页边距(包括上.下.左.右).页面大小(可设置Letter/A3/A4/A5/A6/B4/B5/B6/Envelop DL/Half Letter/Lette ...
- 简单介绍HTTP的请求(get请求和post请求)以及对应的响应的内容
链接解析: https://oa.hbgf.net.cn/login.jsp;jsessionid=47084322738F8DB18D60752944DFD1AA http或者https表示使用的是 ...
- 加老板qq:804691342一起交流学习 致读者的话:曾经的我们很年少,现在我们要为理想的路疯狂的走下去。
慕课网 实战班 就业班 2019年12月1号 更新资料整理 300套 新更课程 百度网盘资料链接: 链接:https://pan.baidu.com/s/1qORPsgM6ukDPOSjU5ck5yA ...
- C++模板编程与宏编程经验谈
C++模板编程与宏编程经验谈 有人说C 与C++的不同主要是因为C++支持模板,不要说区别是面向对象化编程,因为C同样能很好的实现对象化编程,面向对象化其实只是思想,在很多语言中都能实现,区别在于实现 ...
- Myeclipse 2017 下载+安装+激活+集成配置【JRE 8+Tomcat 9+MySQL 5.7.29】
Myeclipse 2017 的下载 Myeclipse 2017 下载地址:https://www.jianguoyun.com/p/DTEBo1cQ6LnsBxj9984C Myeclipse 2 ...
- Installing PyCharm
Installing PyCharm| # ...