一、思考一个问题

我们要给定一个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之路] 闭包的更多相关文章

  1. 百万年薪python之路 -- 闭包

    2.闭包 闭包的定义: 闭包是嵌套在函数中的函数. 闭包必须是内层函数对外层函数的变量(非全局变量)的引用. 一句话定义就是:在嵌套函数内,对非全局变量 (且不是本层的变量)的引用 如何判断判断闭包? ...

  2. Python之路【第一篇】python基础

    一.python开发 1.开发: 1)高级语言:python .Java .PHP. C#  Go ruby  c++  ===>字节码 2)低级语言:c .汇编 2.语言之间的对比: 1)py ...

  3. Python之路

    Python学习之路 第一天   Python之路,Day1 - Python基础1介绍.基本语法.流程控制              第一天作业第二天   Python之路,Day2 - Pytho ...

  4. python之路 目录

    目录 python python_基础总结1 python由来 字符编码 注释 pyc文件 python变量 导入模块 获取用户输入 流程控制if while python 基础2 编码转换 pych ...

  5. 说说Python中的闭包 - Closure

    转载自https://segmentfault.com/a/1190000007321972 Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西 ...

  6. Python之路【第十九篇】:爬虫

    Python之路[第十九篇]:爬虫   网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用 ...

  7. Python之路【第十八篇】:Web框架们

    Python之路[第十八篇]:Web框架们   Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...

  8. Python之路【第十七篇】:Django【进阶篇 】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

  9. Python之路【第十六篇】:Django【基础篇】

    Python之路[第十六篇]:Django[基础篇]   Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...

随机推荐

  1. LEN()和DATALENGTH()的区别

    原文:LEN()和DATALENGTH()的区别 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.n ...

  2. 栈与队列基本操作 Java实现

    一.顺序栈 //数组实现顺序栈 public class OrderStack { private String[] elem; private int top; OrderStack(int k) ...

  3. 学习实践:使用模式,原则实现一个C++数据库访问类

    一.概述 在我参与的多个项目中,大家使用libMySQL操作MySQL数据库,而且是源码即复用,在多个项目中有多套相同或相似的源码,这样的复用方式给开发带来了不变,而且libMySQL的使用比较麻烦, ...

  4. python设计购物车

    设计购物车 一需求: 1.启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表 2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额是否够,够就直接扣款,不够就提 ...

  5. python基础知识0-2

    # !/usr/bin/env python # 提示输入用户名和密码 # 验证用户名和密码#     如果错误,则输出用户名或密码错误#     如果成功,则输出 欢迎,XXX! import ge ...

  6. 拜托,别再问我 QPS、TPS、PV、UV、GMV、IP、RPS 好吗?

    关于 QPS.TPS.PV.UV.GMV.IP.RPS 这些词语,看起来好像挺专业.但实际上,我认为是这是每个程序员必懂的知识点了,你可以搞不懂它们怎么计算的,但是你最少要知道它们分别代表什么意思吧? ...

  7. C++入门基础知识(二)

    一:引用 概念:是给一个已经存在的变量取一个别名,编译器不会为引用变量开辟内存空间,它和引用的变量公用一块内存空间. 例如: 类型& 引用变量名(对象名)= 引用实体 int& a = ...

  8. Js 更换html同一父元素下子元素的位置

    //更换两个元素的位置 var exchange=function (el1, el2) { var ep1 = el1[0].parentNode, ep2 = el2[0].parentNode, ...

  9. vs 2017创建类时的默认模板修改

    思路:找到vs 2017安装目录---->找到模板文件---->修改 一般安装目录: C:\Program Files (x86)\Microsoft Visual Studio\2017 ...

  10. 题解 POJ1964/UVA1330/SP277 【City Game】

    题目链接: https://www.luogu.org/problemnew/show/UVA1330 http://poj.org/problem?id=1964 https://www.luogu ...