测开之函数进阶篇・第五篇《递归函数纯函数匿名函数偏函数》
Posted 七月的小尾巴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了测开之函数进阶篇・第五篇《递归函数纯函数匿名函数偏函数》相关的知识,希望对你有一定的参考价值。
递归函数
递归函数的定义
在函数中调用函数自身,我们把这样的函数叫做递归函数
定义递归函数
# 通过递归函数实现阶乘
def fun(n):
if n == 1: # 递归临界点(不再调用函数自身)
return 1
else:
return n * fun(n -1)
递归函数的优点是定义简单, 逻辑清晰. 理论上, 所有的递归函数都可以写成循环的方式, 但循环的逻辑不如递归清晰。使用递归函数需要注意防止栈溢出. 在计算机中, 函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧, 每当函数返回, 栈就会减少一层栈帧. 由于栈的大小不是无限的, 所以, 递归调用的次数过多, 会导致栈溢出. 当尝试调用fact(1000)时, 程序会报错。
总结来说,使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出(即比较占用内存空间).
纯函数
纯函数的概念
简单来说,一个函数的返回结果只依赖于它的参数,并且在执行过程里面没后副作用,我们把这个函数叫做纯函数。
纯函数的3个原则
- 变量都只在函数作用域内获取,作为函数的参数传入
- 不会产生副作用(side effects),不会改变被传入的数据或者其他数据(全局变量)
- 相同的输入保证相同的输出
函数的副作用
副作用是指函数被调用,完成了函数既定的计算任务,但是同时因为访问了外部数据,尤其是因为对数据进行了写操作,从而一定程序的改变了系统环境。
python常用的内置函数
-
map函数:会根据提供的函数对执行序列做映射
str()是python的内置函数,这个例子是把列表/元组/字符串的每个元素变成了str类型,然后以列表的形式返回。
a = list(map(str,'python')) 结果: ['p', 'y', 't', 'h', 'o', 'n']
定义一个函数,使用add方法,将两个列表相加
def add(x, y): return x+y list1 = [1, 2, 3] list2 = [4, 5, 6] a = list(map(add, list1, list2)) print(a)
-
filter 函数
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
下面我们来看filter函数的源代码:
def filter(function_or_none, sequence): # known special case of filter """ filter(function or None, sequence) -> list, tuple, or string Return those items of sequence for which function(item) is true. If function is None, return the items that are true. If sequence is a tuple or string, return the same type, else return a list. """ pass
使用这个函数,我们需要传两个参数。
- function_or_none:判断函数,可以传函数名称或者None
- sequence:可迭代对象
上面这么说可能有写抽象,下面我们来看一下实例
#!/usr/bin/python3 def is_odd(n): # 判断返回奇数 return n % 2 == 1 # 使用 filter进行过滤 tmplist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) newlist = list(tmplist) print(newlist) 结果: [1, 3, 5, 7, 9]
- zip函数
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
# 打包为元祖列表 test = zip([1, 2, 3], [2, 3, 4]) 返回: [(1, 2), (2, 3), (3, 4)]
匿名函数
匿名函数值适用于简单的函数定义。
下面我们来定义一个简单的匿名函数
res = lambda a, b: a + b
print(res(1, 10))
结果:
11
上方的代码,等同于我们我们下方的函数
def test(a, b):
return a + b
但是python中并不知道我们上方通过这个写法去使用lambda函数,匿名函数的定义是函数即用即内存释放。我们上方 res 相当于定义了一个函数,但是这个写法res一直会在内存中,没有被释放。
在python中,匿名函数通常都会结合 filter、map进行使用,如下代码:
li = [1, 2, 22, 30, 55]
res = filter(lambda x: x < 10, li)
print(res)
返回:
[1, 2]
匿名函数还可以结合表达式使用:
res = [(lambda x: x % 5 == 0)(i) for i in range(10)]
三步运算符
假设我们需要判断如下代码
if a>b:
max = a;
else:
max = b;
可以使用三步 表达式完成
max = a if a>b else b
三步表达式和lambda函数一样,可以使我们代码变的简洁。
偏函数
偏函数的定义
在python内置模块functools提供了很多有用的功能,其中一个就是偏函数(partial)。当函数参数太多,需要简化,使用 functools.partial 可以创建一个新函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
偏函数的案例
在我们前面学到的内置函数 filter 中,调用的时候需要传入两个参数,第一个是函数,第二个是我们需要过滤的可迭代类型的数据。
我们可以通过传入不同的过滤条件来过来出来我们需要的数据
li1 = [1, 20, 30, 100, 1001]
filter(lambda x: x > 3, li1)
上方代码中,我们只是过来一个列表的数据,但是如果有多组列表的数据都要过滤呢?我们应该怎么处理?
难道我们要像下面这样,每次过滤一组数据都用lambda函数吗?
li1 = [1, 20, 30, 100, 1001]
li2 = [1, 20, 30, 100, 1001]
li3 = [1, 20, 30, 100, 1001]
li4 = [1, 20, 30, 100, 1001]
filter(lambda x: x > 3, li1)
filter(lambda x: x > 3, li2)
filter(lambda x: x > 3, li3)
filter(lambda x: x > 3, li4)
我们可以再functools.partial 可以创建一个新函数,通过偏函数创建一个新函数,提前传入原函数所需要的参数,让我们在调用的时候更加简单。
from functools import partial
filter2 = partial(filter, lambda x:x>5)
print(list(filter2(li1)))
以上是关于测开之函数进阶篇・第五篇《递归函数纯函数匿名函数偏函数》的主要内容,如果未能解决你的问题,请参考以下文章