轻松理解python中的闭包和装饰器(上)
继面向对象编程之后函数式编程逐渐火起来了,在python中也同样支持函数式编程,我们平时使用的map, reduce, filter等都是函数式编程的例子。在函数式编程中,函数也作为一个变量存在,对应的函数名就是这个变量的名字,我们可以重新对其赋值,例如abs=len, abs( [1,2,3] ) 返回的是数字3。既然函数是个变量那我们就可以将函数做为参数,和返回值进行传递。
首先我们讲解函数做为返回值:
def outFunc():
print 'call outFunc()...' def inFunc():
print 'call inFunc()...' return inFunc #返回定义好的函数
在上面的函数定义中,我们在函数 outFunc 内部又定义了一个函数 inFunc。准确来说是定义了一个函数对象,用 inFunc 做为它的名字。最后外层函数 outFunc 返回变量 inFunc,也就是这个函数对象。我们可以通过调用outFunc获得这个对象:
>>> x = outFunc() # 调用outFunc()
call outFunc()...
>>> x # 变量x是outFunc()返回的函数:
<function inFunc at 0x1037bf320>
>>> x() # x指向函数,因此可以调用
call inFunc()... # 调用x()就是执行inFunc()函数定义的代码
请注意区分返回函数和返回值:
def myabs():
return abs # 返回函数
def myabs2(x):
return abs(x) # 返回函数调用的结果,返回值是一个数值
通过返回函数我们可以把一些计算延迟执行。例如,如果定义一个普通的求和函数:
def calc_sum(lst):
return sum(lst)
调用calc_sum()函数时,将立刻计算并得到结果:
>>> calc_sum([1, 2, 3, 4])
10
但是,如果返回一个函数,就可以“延迟计算”:
def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum
>>> f = calc_sum([1, 2, 3, 4]) # 调用calc_sum()并没有计算出结果,而是返回函数:
>>> f
<function lazy_sum at 0x1037bfaa0>
>>> f() # 对返回的函数进行调用时,才计算出结果:
10
由于可以返回函数,我们在后续代码里就可以决定到底要不要调用该函数。 此外还有一个优点就是内部定义的函数无法被外部访问,例如lazy_sum函数无法被直接调用,只能通过calc_sum进行调用。
同时注意我们在lazy_sum中引用了 calc_sum 的参数 lst, 用 f 接收返回的函数,再调用 f 时我们并没有传递参数,但它仍然可以继续工作,说明 lst 已经被绑定在lazy_sum内部了,成为函数的一部分,我们调用函数自然就可以操作 lst 求得 lst的和。
像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。举例如下:
# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs f1, f2, f3 = count() #进行调用
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。
原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:
>>> f1()
9 # 因为f1现在才计算i*i,但现在i的值已经变为3
因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。
考察下面的函数 f:
def f(j):
def g():
return j*j return g
它可以正确地返回一个闭包g,g所引用的变量j不是循环变量,因此将正常执行。
在count函数的循环内部,如果借助f函数,就可以避免引用循环变量 i 。
def count():
fs = [] for i in range(1, 4):
def f(j):
def g():
return j*j # g所引用的变量j不是循环变量,而是上层函数传递进来的参数
return g r = f(i)
fs.append(r)
return fs f1, f2, f3 = count() #进行调用
print f1(), f2(), f3()
讲完了函数做为返回值,下一节我们讲解函数做为参数和装饰器的相关概念,精彩继续。
轻松理解python中的闭包和装饰器(上)的更多相关文章
- 轻松理解python中的闭包和装饰器 (下)
在 上篇 我们讲了python将函数做为返回值和闭包的概念,下面我们继续讲解函数做参数和装饰器,这个功能相当方便实用,可以极大地简化代码,就让我们go on吧! 能接受函数做参数的函数我们称之为高阶函 ...
- python中的闭包和装饰器
重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器 1.闭包 闭包是python函数中的一个比较重要功能,一般闭包都是用在装饰器上,一般学完闭包就会去学习装饰器,这俩 ...
- 21.python中的闭包和装饰器
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python ...
- Python 中的闭包与装饰器
闭包(closure)是函数式编程的重要的语法结构.闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性. 如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数 ...
- python中的闭包与装饰器
#原创,转载请留言联系 装饰器的本质就是闭包,所以想知道装饰器是什么,首先要理解一下什么是闭包. 闭包 1. 外部函数返回内部函数的引用.2. 内部函数使用外部函数的变量或者参数. def outer ...
- 聊聊Python中的闭包和装饰器
1. 闭包 首先我们明确一下函数的引用,如下所示: def test1(): print("--- in test1 func----") # 调用函数 test1() # 引用函 ...
- python中函数总结之装饰器闭包
1.前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性. 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包. 2.装饰器 装饰器 ...
- 理解Python中的闭包
1.定义 闭包是函数式编程的一个重要的语法结构,函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式).在面向过程编程中,我们见到过函数(function):在面向对象编程中,我们见 ...
- 第十七篇 Python函数之闭包与装饰器
一. 装饰器 装饰器:可以拆解来看,器本质就是函数,装饰就是修饰的意思,所以装饰器的功能就是为其他函数添加附加功能. 装饰器的两个原则: 1. 不修改被修饰函数的源代码 2. 不修改被修饰函数的调用方 ...
随机推荐
- 计时器chronometer补充
项目中要实现关于安卓控件chronometer这部分的功能需求: 1.计时器的功能对用户答题时间进行时间统计,用户答完该题,进入下一题,计时器接续上一题的结束时间继续计时: 2.用户可以跳出答题界面, ...
- Java数据结构整理(一)
ava数据结构内容整理关键字: 数据结构 Collection:List.SetMap:HashMap.HashTable如何在它们之间选择一.Array , ArraysJava所有“存储及随机访问 ...
- jsp分页的不同实现方法
一.代码实现分页 定义四个分页变量 pageNow 表示第几页 该变量是由用户来决定的,因此是变化的 pageCount 表示总共有多少页,该变量是计算出来的, ---考虑算法 pag ...
- H-W平衡
hardy-weinberg平衡:标准定义————如果一个种群符合下列条件:1.种群是极大的:2.种群个体间的交配是随机的,也就是说种群中每一个个体与种群中其他个体的交配机会是相等的:3.没有突变产生 ...
- eclipse 标签标题乱码解决方法
一般出现此类问题都是由于更改本地语言设置引起的. 解决办法: 1.恢复到原来默认的语言和地域 2.更改eclipse主题(Window-->preferences-->General--& ...
- C++第五天学习
回顾: 1.友元 friend 2.运算符重载 类型 operator运算符(参数表) 抽象.封装 类是面向对象程序设计中最基本的概念 类的背后隐藏的思想是数据抽象和封装 是进行封装和数据隐藏的工具, ...
- Bootstrap入门(二十三)JS插件1:模态框
Bootstrap入门(二十三)JS插件1:模态框 1.静态实例 2.动态实例 3.模态框的尺寸和效果 4.包含表单的模态框 模态框经过了优化,更加灵活,以弹出对话框的形式出现,具有最小和最实用的功能 ...
- 【ci框架基础】之部署百度编辑器
在ci框架下加载编辑器,现在复习下内容.我的框架文件名称为ci 1.下载百度编辑器ueditor,http://ueditor.baidu.com/ 一般情况下下载ubuilder版即可,并将uedi ...
- ADO.NET高级应用
ADO.NET事务处理(4个步骤) 1.调用SqlConnection对象的BeginTransaction()方法,创建一个SqlTransaction对象,标志事务开始. 2.将创建的SqlTra ...
- 蓝桥网试题 java 基础练习 回文数
--------------------------------------------------------------------- 没必要枚举出所有四位数 四位数里是回文的数都有一个特性,是什 ...