高阶函数
- First Class Object
- 函数在Python中是一等公民
- 函数也是对象,可调用的对象
- 函数可以作为普通变量、参数、返回值等等
- 高阶函数
- 数学概念y=g(f(x))
- 在数学和计算科学中,高阶函数应当是至少满足下面一个条件的函数
- 接受一个或多个函数作为参数
- 输出一个函数
- 计数器
# 错误代码
def counter(base):
def inc(step=1):
base += step # 会报错,因为base没有被定义
return base
return inc
----------------------------------
UnboundLocalError: local variable 'base' referenced before assignment
- 分析:
- 函数couter是不是一个高阶函数
- 上面代码有没有什么问题的怎样改进
- 如何调完成计数功能
- fl=counter(5)和f2=counter(5),请问f1和f2相等吗?
# 正确
def counter(base):
def inc(step=1):
nonlocal base
base += step # 会报错,因为base没有被定义
return base
return inc
c = counter(10)
print(c())
f1 = counter(5) # 内层嵌套是局部标识符,局部变量,每次调用的局部变量是重新调用的,产生不同的内存地址
f2 = counter(5)
print("f1 == f2 :{}".format((f1 == f2))) # 函数对象比较,调用的函数对象内存地址不一样
print("f1 is f2 :{}".format((f1 is f2))) # 函数对象比较,调用的函数对象内存地址不一样
print("f1内存地址={}".format(id(f1)))
print("f2内存地址={}".format(id(f2)))
print("f1() == f2() :{}".format((f1() == f2()))) # 函数返回值比较,返回值都是base,返回值一样
print("f1() is f2() :{}".format((f1() is f2()))) # 函数返回值比较,返回值都是base,返回值一样
print("f1()内存地址={}".format(id(f1())))
print("f2()内存地址={}".format(id(f2())))
---------------
11
f1 == f2 :False
f1 is f2 :False
f1内存地址=2577991932512
f2内存地址=2577991932648
f1() == f2() :True
f1() is f2() :True
f1()内存地址=1509565360
f2()内存地址=1509565360
自定义sort函数
- 排序问题
- 仿照内建函数sorted,请自行实现一个sort函数(不使用内建函数),能够为列表元素排序
- 思路
- 内建函数sorted函数是返回一个
新的列表
,可以设置升序或降序
,可以设置一个排序的函数
。自定义的sort函数也要实现这个功能 - 新建一个列表,遍历原列表,和新列表的值依次比较决定如何插入到新列表中
- 内建函数sorted函数是返回一个
- 思考
- sorted数的实现原理,扩展到map、filter函数的实现原理
sort函数实现
- sort函数实现,下面实现的什么排序?还能改变什么
- 这里的if判断逻辑被写死了,可以写成灵活的
def sort(iterable):
ret = [] # 未来排好序的列表
for x in iterable: # 拿出元素
for i, y in enumerate(ret):
if x > y: # 找到大的就地插入。如果换成x < y,函数什么意思呢?升序排列
# if 这里的判断逻辑被写死了
ret.insert(i, x) # 降序
break
else: # 不大于,说明是最小的,尾部追加
ret.append(x)
return ret
print(sort([9, 1, 2, 5, 4, 3, 7, 6]))
改进函数,使用参数控制
- sort函数实现。用一个参数控制顺序
def sort(iterable, reverse=False): # reverse=False,reverse=Ture,是用来控制升序还是降序排序的参数
ret = []
for x in iterable:
for i, y in enumerate(ret):
flag = x > y if reverse else x < y # 由于reverse=False,所以每次flag=x<y
if flag: # x<y=>Ture, x>y=>False
ret.insert(i, x) # True执行ret.insert(i, x)
break
else:
ret.append(x)
return ret
print(sort([9, 1, 2, 5, 4, 3, 7, 6]))
改进函数,通过匿名函数控制
def sort(iterable, key=lambda a, b: a > b): # a>b是判断条件
ret = []
for x in iterable:
for i, y in enumerate(ret):
if key(x, y): # 函数的返回值是bool,a>b=>Ture,a<b=>False
ret.insert(i, x) # True执行ret.insert(i, x)
break
else:
ret.append(x)
return ret
print(sort([9, 1, 2, 5, 4, 3, 7, 6]))
改进函数,sort函数实现
def sort(iterable, reverse=False, key=lambda a, b: a < b):
ret = []
for x in iterable:
for i, y in enumerate(ret):
flag = key(x, y) if not reverse else not key(x, y)
# 因为not reverse=>True,所以flag=key(x,y)
if flag: # a<b=>True, a>b=>False
ret.insert(i, x) # True执行ret.insert(i, x)
break
else:
ret.append(x)
return ret
print(sort([9, 1, 2, 5, 4, 3, 7, 6]))
内建函数-高阶函数
- sorted(iterable[, key][, reverse])
- 排序
- filter(function, iterable) –> filter object
- 过滤数据
- map(func, *iterables) –> map object
- 映射
sorted(iterab[, key][,reverse])排序
- 返回一个新的列表,对一个可迭代对象的所有元素排序,排序规则为key定义的函数,reverse表示是否排序翻转
- sorted(lst,key=lambda x: 6-x) # 返回新列表
- list.sort(key=lambda x: 6-x) # 就地修改
lst = [1, 2, 3, 4, 5, 6, 7]
print(sorted(lst, key=lambda x: 6 - x)) # 这里x为索引,6-0=6,lst[6]=7
print(lst.sort(key=lambda x:6-x))
-----------------------------------
[7, 6, 5, 4, 3, 2, 1] # 返回新列表
None # 就地修改
filter(funtion, iterable)
- 过滤可迭代对象的元素,返回一个迭代器
- function一个具有一个参数的函数,返回bool
- 例如,过滤出数列中能被3整除的数字
- list(filter(lambda x: x%3==0, [1,9,55,150,-3,78,28,123]))
print(list(filter(lambda x: x%3==0, [1, 9, 55, 150, -3, 78, 28, 123])))
"""
lambda x: x%3==0
同等于
def fn(x):
return x%3==0
"""
------------------------------
[9, 150, -3, 78, 123]
map(function, *iterables) –> map object
- 对多个可迭代对象的元素按照指定的函数进行映射,返回一个迭代器
- list(map(lambda x:2*x+1, range(5)))
- dict(map(lambda x: (x%5,x) , range(500)))
print(list(map(lambda x: 2 * x + 1, range(5))))
print(dict(map(lambda x: (x % 5, x), range(500))))
------------------------------------
[1, 3, 5, 7, 9]
{0: 495, 1: 496, 2: 497, 3: 498, 4: 499}
# 0-4,是通过x%5得出,只能有0,1,2,3,4这几个余数,例如497%5=2,495-499是因为前面的数字不断的被覆盖,最终输出的是最后5个数字
# 延展,zip是否可以作为数据源?
print(dict(map(lambda x,y:(x, y), zip('abcde', range(5)))))
---------------
TypeError: <lambda>() missing 1 required positional argument: 'y'
# 报错了,原因:zip出来的是二元组,二元组不能给fn(x,y),都给了x,y是悬空的,没有被赋值
print(tuple(zip('abcde', range(5))))
---------------
(('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4))
柯里化Currying
- 柯里化
- 指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数
- z = f(x,y)转化为z = f(x)(y)的形式
举例
# 将加法函数柯里化 def add(x, y): return x + y # 转换如下 def add(x): def _add(y): return x + y return _add t = add(4)(5) print(t) -------------------------- 9 # 通过嵌套函数就可以把函数转换成柯里化函数