高阶函数
函数在内存中存储方式跟变量一样,计算机会为函数开辟内存空间存放函数体,同时函数名指向这个内存空间,函数名相当于句柄(内存地址),函数可以赋值给变量,通过变量调用,函数与变量一样也可以作为参数传给另一个函数。
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。
# author:zingerman def add(x,y,func): print(func(x)+func(y)) add(2,-3,abs)#abs是绝对值函数的句柄,指向内存中的函数体,func==abs , func()==abs()
高阶函数之map函数
#map()函数接收两个参数,一个是函数,一个是Iterable # map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。 def f(x): return x*x r=map(f,[1,2,3,4]) #<map object at 0x000001E7E456FF28>返回结果的内存地址 print(list(r)) #[1, 4, 9, 16]
也可以这样:
def f(x,y): return x*y r=map(f,[1,2,3,4],[1,2,3,4]) #<map object at 0x000001E7E456FF28>返回结果的内存地址 print(list(r)) #[1, 4, 9, 16]
一段代码将裂变转化成字符串
高阶函数之reduce函数
reduce
把一个函数作用在一个序列[x1, x2, x3, ...]
上,这个函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算,其效果就是
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
# author:zingerman from functools import reduce #结果24,相当于sum 函数 def f (x,y): return x*y print(reduce(f,[1,2,3,4]))
from functools import reduce def f (x,y): return x*10+y print(reduce(f,[1,2,3,4])) #将[1,2,3,4]转换成1234
def func(x,y): return x*10+y def char2num(s): digter={'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} return digter[s] print(list(map(char2num,'12345'))) #[1, 2, 3, 4, 5] print(reduce(func,map(char2num,'12345'))) #12345 相当与int()函数
from functools import reduce #简化版str2int函数 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} def char2num(s): return DIGITS[s] def str2int(s): return reduce(lambda x, y: x * 10 + y, map(char2num, s))
高阶函数之filter函数
filter()
把传入的函数依次作用于每个元素,然后根据返回值是True
还是False
决定保留还是丢弃该元素。
# author:zingerman #使用filter判断是不是奇数,并保留 def is_odd(n): return n%2==1 print(list(filter(is_odd,[1,2,3,4,5,6])))#[1, 3, 5]
filter()
函数返回的是一个Iterator
,也就是一个惰性序列,所以要强迫filter()
完成计算结果,需要用list()
函数获得所有结果并返回list
装饰器(Decorator) 高阶函数+嵌套函数==》》装饰器
本质:一个返回函数的高阶函数
作用:为其他函数添加附加功能
原则:1.不能修改被装饰函数的源代码
2.不能修改被装饰函数的调用方式
实现装饰器的知识储备:
1.函数即"变量"
2.高阶函数
3.嵌套函数
# author:zingerman import time def deco(func): start_time=time.time() func() end_time=time.time() print('花费的时间%s'%(end_time-start_time)) def test(): time.sleep(1) print('in the test') deco(test)#将test赋值给func,增加了功能,没有改变test的源代码,但是改变了函数的原本调用方式test()
# author:zingerman import time def deco2(func):#deco2(test) func=test deco2函数的目的就是定义deco1函数,并拿到deco1的内存地址 def deco1(): start_time=time.time() func() end_time=time.time() print('花费的时间%s'%(end_time-start_time)) return deco1 def test(): time.sleep(1) print('in the test') test=deco2(test) #想要以test()这种调用方式实现附加功能而不改变test源代码, test() # 只有把deco1赋值给test,然后test()执行,现在的test是加了新功能的deco1 #所以将deco1嵌套入deco2函数,并返回deco1,这样就拿到了deco1的内存地址
# author:zingerman import time def deco2(func):#deco2(test) func=test deco2函数的目的就是定义deco1函数,并拿到deco1的内存地址 def deco1(): start_time=time.time() func() end_time=time.time() print('花费的时间%s'%(end_time-start_time)) return deco1 @deco2 #相当于test=deco2(test) def test(): time.sleep(1) print('in the test') test()
# author:zingerman import time #带参数的装饰器 def deco2(func): def deco1(*args,**kwargs): start_time=time.time() func(*args,**kwargs) end_time=time.time() print('花费的时间%s'%(end_time-start_time)) return deco1 @deco2 #相当于test=deco2(test) def test(x): time.sleep(1) print(x) print('in the test') test(2)
生成器:
python使用生成器对延迟操作提供支持,延迟操作就是在有需要的地方产生结果,而不是立即产生结果
python有两种方法提供生成器:
1.生成器函数:常规函数定义,但是使用yield而不是return返回结果,yield语句每次返回一个结果,之后挂起函数的状态,以便下次从yiled之后开始执行,相当于在yield处产生了一个中断
# author:zingerman def fib (n): #用生成器产生斐波那契数列 a, b = 0, 1 for i in range(n): yield (b) a,b=b,a+b #=fib(10) for i in fib(10): print(i)
2.生成器表达式:类似于列表推导,但是生成器一次产生一个结果,而不是一次就产生一个列表,储存所有结果。 (x**2 for x in range(5))
python中的很多内置函数都是用了迭代器协议去访问对象,而生成器实现了迭代器对象,如for函数,sum函数
>>> sum(x ** 2 for x in xrange(4))
而不必这样写>>> sum([x ** 2 for x in xrange(4)])
# author:zingerman import time def consume(name): print('%s准备吃包子了'%name) while True: baizi=yield print('%s包子来了,被%s吃了'%(baizi,name)) # f=consume('hulida') # f.__next__() # f.send('韭菜馅') def producer(name): c1 = consume('A') c2 = consume('B') c1.__next__() c2.__next__() print("老子开始准备做包子啦!") for i in range(10): time.sleep(1) print("做了1个包子,分两半!") c1.send(i) c2.send(i) producer('hu')
迭代器:
我们已经知道,可以直接作用于for
循环的数据类型有以下几种:
一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;
一类是generator
,包括生成器和带yield
的generator function。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。
可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
可以使用isinstance()
判断一个对象是否是Iterable或
对象:Iterator
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象
from collections import Iterable >>> isinstance([], Iterable) True >>> isinstance({}, Iterable) True >>> isinstance('abc', Iterable) True >>> isinstance((x for x in range(10)), Iterable) True >>> isinstance(100, Iterable) False
>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False