[Python之路] 闭包
一、思考一个问题
我们要给定一个x,要求一条直线上x对应的y的值。公式是y = kx+b。
我们需要用k,b来确定这条直线,则我们实现的函数应该有3个参数:
def line(k, b, x):
print(k * x + b) line(1, 3, 4)
line(1, 3, 5)
line(1, 3, 6)
可以看到,我们每次修改x都要重新传入k和b。
我们也可以用全局变量来实现:
k = 1
b = 3 def line(x):
print(k * x + b) line(4)
line(5)
line(6)
k和b为全局变量,但如果我们想要另外一条不同的直线时,则还需要重新定义k和b的值,同样不合理。而且全局变量会暴露给其他不相关的函数,容易造成冲突,或代码混乱。
用面向对象来实现:
class Line(object):
def __init__(self, k, b):
self.k = k
self.b = b def create_y(self, x):
print(self.k * x + self.b) l1 = Line(1, 3)
l1.create_y(4)
l1.create_y(5)
l1.create_y(6)
用类和对象来实现肯定是可以的,但是这么一个简单的功能使用面向对象比较浪费资源。
二、使用闭包
def line(k, b):
def create_y(x):
print(k * x + b) return create_y l1 = line(1, 3)
l1(4)
l1(5)
l1(6)
从以上代码可以直观的看到,闭包有以下几个条件:
1.在一个外函数中定义了一个内函数。
2.内函数里运用了外函数的临时变量。
3.并且外函数的返回值是内函数的引用。
一个函数结束的时候,会把自己的临时变量都释放给内存,之后变量都不存在了。一般情况下,确实是这样的。但是闭包是一个特别的情况。外部函数发现,自己的临时变量会在将来的内部函数中用到,自己在结束的时候,返回内函数的同时,会把外函数的临时变量和内函数绑定在一起。所以外函数已经结束了,调用内函数的时候仍然能够使用外函数的临时变量。
三、内层函数修改外层函数临时变量
def line(k, b):
multi = 10; def create_y(x):
print((k * x + b) * multi) return create_y l1 = line(1, 3)
l1(4)
l1(5)
l1(6)
假设外层函数中有一个multi变量,这个变量可以提供给内层函数访问,但是如果内层函数想修改这个multi变量怎么办呢?
在python3.x中,我们可以使用nonlocal关键字来实现:
def line(k, b):
multi = 10; def create_y(x):
nonlocal multi
multi = 5
print((k * x + b) * multi) return create_y l1 = line(1, 3)
l1(4)
l1(5)
l1(6)
这个nonlocal类似与global的作用,但是global是用于修改全局变量,而nonlocal是用于修改闭包中的外层临时变量。
如果在python2.x中,则不存在nonlocal关键字,我们可以通过将multi变为可变类型数据来实现:
def line(k, b):
# python2.x中将multi变为列表
multi = [10] def create_y(x):
# 可以对外层函数的列表进行修改
multi[0] = 5
print((k * x + b) * multi[0]) return create_y l1 = line(1, 3)
l1(4)
l1(5)
l1(6)
四、闭包和函数、对象等的区别
函数(包含匿名函数):只是功能代码,不包含数据。
对象:包含数据和功能实现。
闭包:包含数据和功能实现。数据指外层函数接收到的参数以及他的局部变量,功能指内层函数的功能。
当函数、匿名函数、对象和闭包做为实参传递时,他们有什么区别????
1.函数和匿名函数被当做实参传递时,传递的是功能的引用,可以通过该引用调用他们实现的功能。但数据需要另外提供。
2.闭包被当做实参传递时,其实传递了数据+功能。例如:
def line(k, b):
# python2.x中将multi变为列表
multi = [10] def create_y(x):
# 可以对外层函数的列表进行修改
multi[0] = 5
print((k * x + b) * multi[0]) return create_y def function(func):
func(5) function(line(1, 3))
我们可以看到,闭包line被传入function,实际上带着数据k=1,b=3。
而如果是普通函数:
def line_norm(k, b, x):
print(k * x + b) def function(func):
func(1, 3, 5) function(line_norm)
这里的k=1,b=3是function函数自己提供的。
3.对象被当做实参传递时,该对象中的成员属性作为数据,成员方法作为方法,都被传递给function函数。
class Line(object):
def __init__(self, k, b):
self.k = k
self.b = b def create_y(self, x):
print(self.k * x + self.b) line1 = Line(1, 3) def function(inst):
inst.create_y(5) function(line1)
[Python之路] 闭包的更多相关文章
- 百万年薪python之路 -- 闭包
2.闭包 闭包的定义: 闭包是嵌套在函数中的函数. 闭包必须是内层函数对外层函数的变量(非全局变量)的引用. 一句话定义就是:在嵌套函数内,对非全局变量 (且不是本层的变量)的引用 如何判断判断闭包? ...
- Python之路【第一篇】python基础
一.python开发 1.开发: 1)高级语言:python .Java .PHP. C# Go ruby c++ ===>字节码 2)低级语言:c .汇编 2.语言之间的对比: 1)py ...
- Python之路
Python学习之路 第一天 Python之路,Day1 - Python基础1介绍.基本语法.流程控制 第一天作业第二天 Python之路,Day2 - Pytho ...
- python之路 目录
目录 python python_基础总结1 python由来 字符编码 注释 pyc文件 python变量 导入模块 获取用户输入 流程控制if while python 基础2 编码转换 pych ...
- 说说Python中的闭包 - Closure
转载自https://segmentfault.com/a/1190000007321972 Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西 ...
- Python之路【第十九篇】:爬虫
Python之路[第十九篇]:爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用 ...
- Python之路【第十八篇】:Web框架们
Python之路[第十八篇]:Web框架们 Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...
- Python之路【第十七篇】:Django【进阶篇 】
Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...
- Python之路【第十六篇】:Django【基础篇】
Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...
随机推荐
- 二叉树(Java实现)
一.常见用语 1.逻辑结构:描述数据之间逻辑上的相关关系.分为线性结构(如,字符串),和非线性结构(如,树,图). 2.物理结构:描述数据的存储结构,分为顺序结构(如,数组)和链式结构. 3.结点的度 ...
- 基于Docker 搭建 Jenkins
⒈下载镜像 要使用最新的LTS: docker pull jenkins/jenkins:lts 要使用最新的每周 docker pull jenkins/jenkins ⒉运行 docker run ...
- Spring系列二:IoC 容器
还君明珠双泪垂,恨不相逢未嫁时. 概述 Spring IoC容器是Spring框架的核心.只需要进行简单的容器配置,就可以将创建对象,使用对象,销毁对象联系在一起,从而管理从创建对象到销毁对象的整个生 ...
- c++学习笔记之类模板
C++ 除了支持函数模板,还支持类模板(Class Template).函数模板中定义的类型参数可以用在函数声明和函数定义中,类模板中定义的类型参数可以用在类声明和类实现中.类模板的目的同样是将数据的 ...
- 进阶Python:装饰器 全面详解
进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...
- F. 汤圆防漏理论
ghc很喜欢吃汤圆,但是汤圆很容易被粘(zhān)漏. 根据多年吃汤圆经验,ghc总结出了一套汤圆防漏理论: 互相接触的汤圆容易粘(zhān)在一起,并且接触面积不同,粘(zhān)在一起的粘(niá ...
- X86逆向13:向程序中插入Dll
本章我们将学习Dll的注入技巧,我们将把一个动态链接库永久的插入到目标程序中,让程序在运行后直接执行这个Dll文件,这一章的内容也可以看作是第八课的加强篇,第八课中我们向程序中插入了一个弹窗,有木有发 ...
- WCF寄宿windows服务一
如果只是寄宿单个wcf服务,方法很简单,步骤:1.创建好一个windows服务.关于windows服务内容见:http://www.cnblogs.com/zhaow/p/7866916.html2. ...
- vue axios异步请求django
1,配置请求路径 (1),vue中的请求路径要与django视图路径相同. (2),vue中的路由路径也要和django视图路径相同,比如视图路径为127.0.0.1:8000:home/index, ...
- Sql Server 导出数据库表结构的SQL查询语句
--导出数据库所有表 SELECT 表名 Then D.name Else '' End, 表说明 Then isnull(F.value,'') Else '' End, 字段序号 = A.colo ...