轻松理解python中的闭包和装饰器 (下)
在 上篇 我们讲了python将函数做为返回值和闭包的概念,下面我们继续讲解函数做参数和装饰器,这个功能相当方便实用,可以极大地简化代码,就让我们go on吧!
能接受函数做参数的函数我们称之为高阶函数,例如filter, map, reduce这些函数
可以定义一个函数作为高阶函数例如:
def func(x, y, f):
return f(x)+f(y)
可以这样调用func(2,-1,abs) 函数返回结果为3
有些时候,我们不需要显式地定义传入的函数,直接传入匿名函数更方便。
在Python中,对匿名函数提供了支持。以map()函数为例,计算 f(x)=x2 时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:
1 >>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
2 [1, 4, 9, 16, 25, 36, 49, 64, 81]
通过对比可以看出,匿名函数 lambda x: x * x 实际上就是:
def f(x):
return x * x
关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。
使用匿名函数,可以不必定义函数名,直接创建一个函数对象,很多时候可以简化代码:
1 >>> sorted([1, 3, 9, 5, 0], lambda x,y: -cmp(x,y))
2 [9, 5, 3, 1, 0]
返回函数的时候,也可以返回匿名函数:
1 >>> myabs = lambda x: -x if x < 0 else x
2 >>> myabs(-1)
3 1
4 >>> myabs(1)
5 1
有些时候我们定义了一个函数,想在运行时动态增加功能,又不想改动函数本身的代码,这就可以用高阶函数实现: 可以接收一个函数作为参数对其包装,返回函数:
1 def f1(x):
2 return x*2
3
4 def new_fn(f):
5 def fn(x): # 定义一个内层函数
6 print "call: " + f.__name__ + "()"
7 return f(x) # 再内层函数中调用传递进来的函数
8
9 return fn # 返回内层函数
10
11 g1 = new_fn(f1) #进行调用
12 print g1(2)
执行上面代码,输出
call: f1()
4
可见我们将一个 f1 包装了一下,在它原有计算x*2的功能上又输出了自己的函数名。整个过程中我们定义的内层函数 fn 是关键,它在内部使用的是new_fn传递进来的参数 f ,这不就是前面讲的闭包吗? fn在添加其他功能后又调用了原来 f。
我们甚至可以这样
1 f1 = new_fn(f1)
2 print f1(2)
上面的代码输出结果一样,但是将f1传递进去又得到一个f1, 一样的调用方法但新的功能比以前的那个高级。
上面代码中f1 = new_fn(f1)这样的写法未免太过蹩脚,我们可以利用python提供的 装饰器 语法优雅的实现。上面new_fn的定义不变,我们只需要重新定义 f1 就可以了,如下:
1 @new_fn
2 def f1(x):
3 return x*2
4
5 @new_fn
6 def f2(x):
7 return x/2
8
9 print f1(2)
10 print f2(2)
输出如下:
call: f1()
4
call: f2()
1
我们在函数前面加了@new_fn就代表了对f1这个函数进行装饰加工,以后调用f1就直接调用了加工后的f1, 对于f2也这样,用起来一切很方便。
注意上面的代码只能对 f1 这样单个参数的函数能进行装饰,如果需要装饰两个参数的函数那new_fn就无法实现了,其实也很简单,我们只需要使用*args, **kw,就能保证任意个数的参数总是能正常调用,如下。
1 def new_fn(f):
2 def fn(*args, **kw): # 可以传入任意参数
3 print 'call ' + f.__name__ + '()...'
4 return f(*args, **kw)
5 return fn
6
7 @new_fn
8 def add(x, y):
9 return x + y
10
11
12 print add(1, 2)
其实仔细观察我们发现虽然调用add传递了参数1,2, 但是它只是传递到了装饰器中,也就是上面的 fn 中,我们可以随时在装饰器中改变它的参数然后再传递给 f。
经过上面的步骤现在总算是可以正常实现功能了。但是如果我们再提出需求呐(程序员总是害怕这一点
轻松理解python中的闭包和装饰器 (下)的更多相关文章
- 轻松理解python中的闭包和装饰器(上)
继面向对象编程之后函数式编程逐渐火起来了,在python中也同样支持函数式编程,我们平时使用的map, reduce, filter等都是函数式编程的例子.在函数式编程中,函数也作为一个变量存在,对应 ...
- 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. 不修改被修饰函数的调用方 ...
随机推荐
- iOS 加载动态库报错问题
dyld: Library not loaded: @rpath Referenced from: Reason: no suitable image found. Did find: 要么使用静态 ...
- Violin 琴弦介绍
共四根弦,从粗到细: 第四弦:音名:G:唱名:Sol 第三弦:音名:D:唱名:Re 第二弦:音名:A:唱名:La 第一弦:音名:E:唱名:Mi
- 关于IE6、IE7、IE8实现盒子阴影shadow的几个注意点
通常,我们实现盒阴影都是通过这段代码来实现的 -moz-box-shadow: 3px 3px 4px #000; -webkit-box-shadow: 3px 3px 4px #000; box- ...
- 2.9. Scalar Properties for Primitive Data Types 选项(Core Data 应用程序实践指南)
该选项的意思是,“用Scalar特性来表示原始数据类型”.什么意思,妈妈米呀,这是我学这门课程遇到的最难懂的概念. scalar properties,是复数,也就是说是 “分等级的属性”.那么,大概 ...
- HDU-2573-Typing
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2573 这题把%s与gets()的输入法搞混了一直感觉没有错,就是找不出哪里错了, 题目思路不是很难. ...
- node源码详解(六) —— 从server.listen 到事件循环
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource6 本博客同步在https://cnodejs.o ...
- FP Tree算法原理总结
在Apriori算法原理总结中,我们对Apriori算法的原理做了总结.作为一个挖掘频繁项集的算法,Apriori算法需要多次扫描数据,I/O是很大的瓶颈.为了解决这个问题,FP Tree算法(也称F ...
- POJ3728 LCA RMQ DP
题意简述:给定一个N个节点的树,1<=N<=50000 每个节点都有一个权值,代表商品在这个节点的价格.商人从某个节点a移动到节点b,且只能购买并出售一次商品,问最多可以产生多大的利润. ...
- ADXL345经验总结,采用SPI和I2C总线操作
一. ADXL345简介 ADXL345是ADI公司推出的三轴(x,y,z)iMEMS数字加速度计(digital accelerometer),具有在16G下高分辨率(13Bit)测量能 ...
- 源码(07) -- java.util.Iterator<E>
java.util.Iterator<E> 源码分析(JDK1.7) ----------------------------------------------------------- ...