Python--高阶函数、函数嵌套、名称空间及变量作用域、闭包、装饰器
1.高阶函数(map/reduce/filter)
高阶函数是指函数的参数可以是函数
这篇总结几个常用的高阶函数:map/reduce/filter
map函数、reduce函数、filter函数都是Python中的内建函数。
map函数
map函数的作用是将一个函数作用于一个序列的每一个元素,一行代码即可完成,不需要用我们平常喜欢用的循环。map将运算进行了抽象,我们能一眼就看出这个函数是对一个序列的每个元素进行了同样的一个操作。map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
注意第一个参数只需要传函数名,而这个函数参数就是后面的序列的每一个元素传入。由于map的结果是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。
def mul(x):
return x*x r = list(map(mul, [1,2,3,4,5,6,7,8,9]))
#或简化:
r = list(map(lambda x:x*x, [1,2,3,4,5,6,7,8,9]))
reduce函数
reduce也是把一个函数作用在一个序列上,它必须接收两个参数,把前两个参数计算的结果作为第一个参数继续和序列的下一个元素进行累积计算,即:
reduce(f, [x1, x2, x3, x4,x5]) = f(f(f(f(x1, x2), x3), x4),x5)
例1:
#将list转化成一个整数
from functools import reduce
L=[1,2,5,8]
print(reduce(lambda x,y: x*10+y, L))#1258
注意:
reduce()要从functools中import
lambda函数是匿名函数,我们可以用lambda函数进行一些简单进行,省去定义函数。lambda函数的参数可以0个或多个,参数用逗号分隔。参数后跟冒号,再跟表达式,返回的是计算的结果。
例2:
#将字符串转化成整数
from functools import reduce
def str2int(s):
def str2num(x):
DIGITS={'': 0, '': 1, '': 2, '': 3, '': 4, '': 5, '': 6, '': 7, '': 8, '': 9}
return DIGITS[x]
return reduce(lambda y,z:y*10+z, map(str2num,s))
print('')#9748
#将字符串转化成浮点数
from functools import reduce
def str2float(s):
DIGITS = {'': 0, '': 1, '': 2, '': 3, '': 4, '': 5, '': 6, '': 7, '': 8, '': 9}
def str2num(a):
return DIGITS[a]
return reduce(lambda x,y:x*10+y, map(str2num, s.split('.')[0])) +reduce(lambda x,y:x*10+y, map(str2num, s.split('.')[1]))*10**(-len(s.split('.')[1]))
filter函数
filter函数和map函数类似,接收两个参数,一个是函数,第二个是一个序列。filter函数把传入的函数依次作用于序列的每一个元素,根据函数的返回值是True还是False决定保留或删除该元素。
如我们想找出一个序列中的所有偶数,等等。
#删除序列中元素的所有空格
def not_empty(s):
return s and s.strip() list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
# 结果: ['A', 'B', 'C']
#返回一个范围内的所有回数(从左至右和从右至左,是同一个数字)
def is_palindrome(n):
s=str(n)
return s[::1] == s[::-1] # 测试:
output = filter(is_palindrome, range(1, 200))
print(list(output))
#结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]
2.函数嵌套
函数嵌套分为函数嵌套定义和函数嵌套调用。
函数嵌套定义即在一个函数定义的函数体内定义另外一个函数:
#函数嵌套定义示例
def f():
print("f")
def f1():
print("f1")
def f2():
print("f2")
f2()
f1() f()
#结果:f
# f1
# f2
还可以将嵌套定义的函数作为return的参数(这种用法在下面的闭包中详细介讲解),下面的代码跟上面的代码输出结果一致。
def f():
print("f")
def f1():
print("f1")
def f2():
print("f2")
return f2
return f1 t1 = f()#t1就是f1
t2 = t1()#即调用f1(),t2就是f2
t3 = t2()#即调用f2()
函数嵌套调用就是在一个函数体里面调用另外一个函数。
例:在func2中调用了func1函数
#函数嵌套调用示例
def func1(x,y):
return x*y def func2(a,b,c):
r1 = func1(a,b)
r2 = func1(a,c)
r3 = func1(b,c)
print(r1,r2,r3) func2(2,5,9)
#结果:10 18 45
3.名称空间及变量作用域
名称空间就是存储名字的地方,Python中变量与值的绑定关系的地方。分为三种:内置名称空间、全局名称空间、局部名称空间。
内置名称空间:Python解释器启动时首先加载的
全局名称空间:执行脚本时,以脚本内容为基础,加载全局名称空间
局部名称空间:在运行脚本的过程中,如果调用函数,就会临时产生局部名称空间
内置名称空间和全局名称空间对应的作用域是全局的,而局部名称空间对应的作用域是局部的。
因此我们在脚本里应该尽可能少地定义全局有效的变量,这样耗内存且拖慢运行速度。
变量的作用域是定义的时候就固定了的,对于函数中的参数变量,是在函数定义阶段固定的,跟函数的调用位置不相关。
在函数内定义的变量一般只在函数内部起作用,不能再函数外部使用。
a = 99
print(a)#
def addn():
a = 100#这里定义的a只在本函数内部有作用
print(a)
a += 1
print(a)
addn()#100 101
print(a)#
a = 200
print(a)#
4.闭包
上面讲到的函数嵌套定义中的第二部分示例其实就是闭包。闭包返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。
闭包中内层的函数通过nonlocal关键字可以使得其可以使用外层函数中定义的变量。
下面的例子中,如果n不指定为nonlocal,程序会报错
#实现一个计数器
def counter():
n=0
def incr():
nonlocal n
x=n
n+=1
return x
return incr c=counter()
print(c())#
print(c())#
print(c())#
使用闭包可以延迟计算,先将函数包起来,需要用的时候再调用。
5.装饰器
我们在写Python程序的时候往往需要输出一些日志信息,但是不希望去改变函数内部的代码,那么给函数动态增加如输出日志的功能,可以用装饰器实现。
装饰器有两种:不带参数和带参数的装饰器。
#不带参数的装饰器
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
#带参数的装饰器
#text是需要传入的参数
import functools
def log1(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))#func.__name__返回变量func对应的函数名
return func(*args, **kw)
return wrapper
return decorator
装饰器的输入是函数,返回值也是函数。将装饰器放在要定义的函数的前面(使用@),即可实现在调用定义的函数的时候会运行一次装饰器。
@log
def now():
print('2019-08-10')
@log1('tt')
def now():
print('2019-08-10')
那么对于上述不带参数的装饰器,调用now()函数的时候的输出如下:相当于执行了now = log(now)
>>>now()
call now():
2019-08-10
对于上述带参数的装饰器,调用now()函数的时候的输出如下:相当于执行了now = log('tt')(now)
>>>now()
tt now():
2019-08-10
多个装饰器可以同时放在函数定义的上面
@log1
@log2
@log3
def now():
pass #相当于:now = log1(log2(log3(now)))
最后放一个装饰器的例子。
用一个装饰器为多个函数加上认证功能,登录成功一次后在超时时间内进行其他操作(运行下一个函数)无需重复登录,超过了超时时间,则必须重新登录。
#装饰器为多个函数加上认证功能,登录成功一次后在超时时间内进行其他操作(运行下一个函数)无需重复登录,超过了超时时间,则必须重新登录
import time,random user = {'name':None, 'login_time':False, 'timeout':0.0000002} def log(func):
def wrapper(*args,**kwargs):
if user['name']:
timeout=time.time()-user['login_time']
if timeout < user['timeout']:
return func(*args,**kwargs)
else:
print("登录超时,请重新登录!")
name=input('name: ').strip()
password=input('pwd: ').strip()
if name == 'tt' and password == '':
user['name']=name
user['login_time']=time.time()
res=func(*args,**kwargs)
return res
return wrapper @log
def first():
print("welcome to login!") @log
def home():
print("welcome to home!") first()
home()
当我们在首次登录后会执行first函数里面的代码,再执行home函数时已经超过超时时间,这时的输出如下,需要再次输入用户名和密码。
name: tt
pwd: 123
welcome to login!
登录超时,请重新登录!
name:
而如果未超过超时时间,home函数能够直接执行,输出:
name: tt
pwd: 123
welcome to login!
welcome to home!
Python--高阶函数、函数嵌套、名称空间及变量作用域、闭包、装饰器的更多相关文章
- 【0809 | Day 12】可变长参数/函数的对象/函数的嵌套/名称空间与作用域
可变长参数 一.形参 位置形参 默认形参 二.实参 位置实参 关键字实参 三.可变长参数之* def func(name,pwd,*args): print('name:',name,'pwd:',p ...
- python 函数及变量作用域及装饰器decorator @详解
一.函数及变量的作用 在python程序中,函数都会创建一个新的作用域,又称为命名空间,当函数遇到变量时,Python就会到该函数的命名空间来寻找变量,因为Python一切都是对象,而在命名空间中 ...
- Python入门之函数的嵌套/名称空间/作用域/函数对象/闭包函数
本篇目录: 一.函数嵌套 二.函数名称空间与作用域 三.函数对象 四.闭包函数 ============================================================ ...
- python之函数对象、函数嵌套、名称空间与作用域、装饰器
一 函数对象 一 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 #3 返回值可以是函数 #3 可以当作容器类型的元素 二 利用该特性,优雅的取代多分支的if de ...
- python基础知识13---函数对象、函数嵌套、名称空间与作用域、装饰器
阅读目录 一 函数对象 二 函数嵌套 三 名称空间与作用域 四 闭包函数 五 装饰器 六 练习题 一 函数对象 1 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 ...
- python之旅:函数对象、函数嵌套、名称空间与作用域、装饰器
一 函数对象 一 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 #3 返回值可以是函数 #3 可以当作容器类型的元素 二 利用该特性,优雅的取代多分支的if de ...
- python函数篇:名称空间、作用域和函数的嵌套
一.名称空间:(有3类) (1)内置名称空间(全局作用域) (2)全局名称空间(全局作用域) (3)局部名称空间(局部作用域) 关于名称空间的查询: x=1 def func(): print('fr ...
- Python 函数对象-函数嵌套-名称空间与作用域-闭包函数
今日内容: 1. 函数对象 函数是第一类对象: 指的是函数名指向的值可以被当中数据去使用 1.可以被引用 2.可以当做参数传给另一个函数 3.可以当做一个函数的返回值 4.可以当做容器类型的元素 2. ...
- Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global以及nolocal的用法
Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global以及nolocal的用法 目录 Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global ...
随机推荐
- JVM(一):久识你名,初居我心
聊聊JVM JVM,一个熟悉又陌生的名词,从认识Java的第一天起,我们就会听到这个名字,在参加工作的前一两年,面试的时候还会经常被问到JDK,JRE,JVM这三者的区别. JVM可以说和我们是老朋友 ...
- 【Machine Learning·机器学习】决策树之ID3算法(Iterative Dichotomiser 3)
目录 1.什么是决策树 2.如何构造一棵决策树? 2.1.基本方法 2.2.评价标准是什么/如何量化评价一个特征的好坏? 2.3.信息熵.信息增益的计算 2.4.决策树构建方法 3.算法总结 @ 1. ...
- Apache Flink 1.9 重大特性提前解读
今天在 Apache Flink meetup ·北京站进行 Flink 1.9 重大新特性进行了讲解,两位讲师分别是 戴资力/杨克特,zhisheng 我也从看完了整个 1.9 特性解读的直播,预计 ...
- 控制台出现_ob_:Obsever
我遇到一个问题:我的代码想让他点击之后得到经纬度坐标数组,然后我就这样写了 然而控制台却读取出了
- 使用RedisMQ 做一次分布式改造
引言 熟悉TPL Dataflow博文的朋友可能记得这是个单体程序,使用TPL Dataflow 处理工作流任务, 在使用Docker部署的过程中, 有一个问题一直无法回避: 在单体程序部署的瞬间会有 ...
- Extjs4 combobox autoLoad: true 时,加载两次
问题是这样的,combobox 远程加载数据时,当我们把 store 设置为 autoLoad: tue, 时,这样页面加载时,store 会load 一次,但是我们在第一次点击 下来框时,他还会 ...
- 【译】尝试使用Nullable Reference Types
随着.NET Core 3.0 Preview 7的发布,C#8.0已被认为是“功能完整”的.这意味着它们的最大亮点Nullable Reference Types,在行为方面也被锁定在.NET Co ...
- 关于asp.net调用gemalto超级狗api的具体实现
鉴于网上关于超级狗的具体操作并不详细,我把我所知道的写下来,希望能给有需求的网友做个参考.软件外壳保护我就不说了,没有什么难度,供应商也会提供文档,一步一步操作即可.我要说的是用于保护发给客户的程序, ...
- Activiti6系列(5)- 核心API
前言 本来想把<疯狂工作流讲义-activiti6.0>这本书里面的实例拿过来,但是这本书我看完后,认为里面编写的activiti6的核心API代码片段不是很清晰,有不少需要雕琢的地方才好 ...
- 【游记】NOIP2018初赛
声明 本文最初的版本创建之时,本人甚至只是个电脑的小白,因而不太会用电脑编辑文字,最初的版本写在一个Word文档里,被随意的丢弃在我杂乱无比的网盘的某一个角落,直到我决定整理自己的成长历程,将散落的游 ...