函数进阶

递归函数

定义一个函数在函数的内部调用自身,如果不设置递归边界,将死循环无限调用知道被pycharm等ide观测到抛出异常终止
案例1:

  1. def fun():
  2. if n == 0:
  3. return n
  4. else:
  5. return n*fun(n-1)
  6. # 在当前函数中,就是当n=0的时候停止调用自身

纯函数

纯函数的概念,简单来说,一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用(副作用请看到后面),就吧这个函数叫做纯函数.
不管在什么时候调用,传入的参数相同,返回的结果就一定是一样的.

纯函数的三原则

  1. 变量都只在函数作用域内获取,作为函数的参数传入
  2. 不会产生副作用,不会改变被传入的数据或者其他数据(全局变量)
  3. 相同的输入保证相同的输出

    函数的副作用

    副作用指函数被调用,完成函数既定的运算任务,但因为访问了外部数据,尤其是因为对外部数据进行了操作,从而一定程度的改变了系统环境.
    内置函数都是纯函数,内置函数一般都是python中的内置类.
    常用的内置函数 map函数,会根据提供的函数对指定序列做映射,filter函数,用于过滤序列

    内置函数三剑客

    filter

    接收两个参数,源码记述中其本质为一个python类
    第一个参数为含有计算规则的函数,第二个为可迭代对象.
    案例1
    1. def fun():
    2. # return true
    3. return n < 5
    4. li =[1,2,3,4,5,6,7,8]
    5. fil = filter(fun,li) # 两个参数,第一个为函数,第二个为可迭代对象
    6. # 执行逻辑,将可迭代对象中的元素遍历传入fun进行计算
    7. print(type(fil)) # 返回为一个filter对象
    8. print(list(fil)) # 可以通过转换成list直接打印出来
    其返回的即是列表li中所有满足fun中小于5的值,且组合成一个新的序列.

    map

    同filter一样,接收两个参数,直接返回的是一个map对象.
    filter会根据返回值判断是否将值放入新的序列中,map则会直接将返回值拿过来,相当于将可迭代对象便利传入func中并取到func运行之后的返回值.
    使用场景常常为需要统一处理一批数据的时候.
    案例2
    1. li_source = [ i for in range(1,20)]
    2. def func(n):
    3. # 写一个生成斐波那契数列的map函数方法
    4. if n==1 or b==2 :
    5. return 1
    6. else :
    7. return func(n-1) + func(n-2)
    8. fib = map(func,li_source)
    9. # 执行逻辑即是,便利li_source将其中元素迭代传入func,按照其内部逻辑执行并返回

    zip

    主要用来打包数据,接收数据与前两者不同,可以接收多个可迭代对象.
    吧第一个可迭代元素遍历与第二个可迭代对象打包成元组.
    之后强转为dict可以生成字典. 这种处理方式经常用来操作测试用例数据
    长短不一的时候会自动取最短的,舍弃多余项

    匿名函数

    匿名函数一种特殊的函数,不用def去定义,也不用给函数起名字,通过lambda表达式来定义.
    这种函数称为匿名函数
    写法 : lambda 参数 : 表达式 (返回值)
    ex: lambda var : var1 *2
    lambda a,b: a+b
    前面相当于两个没有函数的参数,冒号后面相当于return,那么如何传参数呢?
    匿名函数的适用场景 : 简单的函数定义(只有一个表达式的那种)
    我们按照传统函数的思路来写个传参调用,
    lamdba a,b : a+b(1,2)
    但是匿名函数是不能按照传统参数那样直接在函数后添加()进行调用.
    按照上面的写法,会将()中的内容也当作表达式的一部分,并不会被当成是参数
    解决方式是(lambda a,b:a+b)(参数1,参数2),通过()将函数体与参数分割开来即可,
    匿名函数实战的常规写法,lambda是直接调用,直接使用,用完就丢,释放内存,用变量去保存反而会浪费一块内存去保存.
    实例
    1. iterator = filter(lambda x: x<10 ,li) # 所以lambda常常和filter,map一起使用,
    2. # 直接使用,用完就丢掉
    3. print(list(iteraotr))
    4. # 列表推导式中也可以使用
    5. li2 = [(lambda x: x % 2==0)(i) for i in range(10)]
    6. # 其执行逻辑是,for循环遍历出i的值为1-10,然后i作为参数传入前面的匿名函数,最终生成值形成新列表

    三目运算符

    三木运算符,适用于一个条件判断,成立,做A,不成立,做B
    python版本的语法支持为
    为真的时候的结果 if 判断条件 else 为假的时候的结果 ( 与其他语言不同的地方是没有冒号
    写起来会有中写英语的感觉.

    偏函数

    什么是偏函数呢?
    python的内置模块functools中提供了很多有用的功能,其中一个就是偏函数 partial
    偏函数的作用
    当函数的参数个数太多,需要进行简化的时候,使用functools.partial可以创建一个新的函数,这个函数可以固定住原函数的部分参数,从而简化调用时的使用.
    在感觉上接近于对函数的在封装,方便进行调用

partial()是不定长参数,可以封装很多东西进去,函数写第一位,后面则是参数位
上实例

  1. li =[1,2,3,4,5,6,7,8,9]
  2. li1 =[1,2,3,4,5,6,7,8,9]
  3. li2 =[1,2,3,4,5,6,7,8,9]
  4. li3 =[1,2,3,4,5,6,7,8,9]
  5. li4 =[1,2,3,4,5,6,7,8,9]
  6. li5 =[1,2,3,4,5,6,7,8,9]
  7. # 有以上这么多列表等待处理.
  8. # 需求为 ,需要过滤掉小于5的元素
  9. filter(lambda x:x<5,li) # 通过filter的方法处理数据,取满足条件的数据组成新的序列
  10. # 但是如此多的列表,如果要写的话会出现很多冗余代码,此时使用偏函数方法就很合适了
  11. from functools import partial
  12. p = partial(filter,lambda x:x<5)
  13. # 之后调用
  14. p(li) # 就可以简单的调用了