【廖雪峰Python教程】四、函数式编程

参考资料Python教程 - 廖雪峰的官方网站 (liaoxuefeng.com)

四、函数式编程(Functional Programming)

纯粹的函数式编程语言编写的函数没有变量,由于Python允许使用变量,因此,Python不是纯函数式编程语言。
  1. 高阶函数Higher-order function

​ 变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

map/reduce函数
  • map()函数

    • 【输入】两个参数:函数 + Iterable

    • 【输出】map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回

    • 举例:把函数f(x)=x2作用在list [1, 2, 3, 4, 5, 6, 7, 8, 9]的每个元素上

      •   >>> def f(x):
          ...     return x * x
          ...
          >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
          >>> list(r)
          [1, 4, 9, 16, 25, 36, 49, 64, 81]
        
    • 代码简化 注意:在leetcode中常见这种写法,且处理数据时经常用到map()函数

      •   >>> list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
          [1, 4, 9, 16, 25, 36, 49, 64, 81]
        
  • reduce()函数

    • 【输入】:两个参数

    • 【作用】:reduce把结果继续和序列的下一个元素做累积计算→reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

    • 举例:序列求和

      •   >>> from functools import reduce
          >>> def add(x, y):
          ...     return x + y
          ...
          >>> reduce(add, [1, 3, 5, 7, 9])
          25
        
filter()函数
  • 用于过滤序列(别和map()混淆,这里不对原数据进行改变)

  • 【输入】一个函数和一个序列

  • 【作用】把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。(即:对可迭代对象进行逐一操作,将满足表达式的挑选出来)

  • 举例

    •   def is_odd(n):
            return n % 2 == 1
        list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
        # 结果: [1, 5, 9, 15]
      
sorted()函数
  • 排序算法:排序的核心是比较两个元素的大小

    • 数字:直接比较
    • 其他类型:通过函数抽象出来
  • sorted()函数

    • 是一个高阶函数。用sorted()排序的关键在于实现一个映射函数。

    • 可以直接对list进行排序 sorted([36, 5, -12, 9, -21])

    • 可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序 sorted([36, 5, -12, 9, -21], key=abs)

      • key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序
    • 默认情况下,对字符串排序,按照ASCII的大小比较

      • 由于'Z' < 'a',结果,大写字母Z会排在小写字母a的前面。(先排大写,再排小写)

        •   >>> sorted(['bob', 'about', 'Zoo', 'Credit'])
            ['Credit', 'Zoo', 'about', 'bob']
          
      • 如果想要忽略大小写,需要先转换为相同大/小写

        •   >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
            ['about', 'bob', 'Credit', 'Zoo']
          
      • 如果想要反向排序,让z排前面

        •   >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
            ['Zoo', 'Credit', 'bob', 'about']
          
  1. 返回函数 (需配合实际做题加强理解)
  • 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。(返回的不是运算结果)

  • 闭包

    • 内层函数引用了外层函数的局部变量,即当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

    • ❗返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。❗

    • 如果一定要引用循环变量怎么办?

      • 再创建一个函数,用该函数的参数绑定循环变量当前的值

      • 因此无论该循环变量后续如何更改,已绑定到函数参数的值不变

      •   def count():
              def f(j):
                  def g():
                      return j*j
                  return g
              fs = []
              for i in range(1, 4):
                  fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
              return fs
        
      •   # 对应结果
          >>> f1, f2, f3 = count()
          >>> f1()
          1
          >>> f2()
          4
          >>> f3()
          9
        
    • ❗ 使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量。❗

      • 如果只是读外层变量的值,我们会发现返回的闭包函数调用一切正常
      • 但是,如果对外层变量赋值,会报错
    • tips:返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

  1. 匿名函数
  • 匿名函数lambda x: x * x实际上就是:

    •   def f(x):
            return x * x
      
  • 关键字lambda表示匿名函数,冒号前面的x表示函数参数。

  • 限制:只能有一个表达式,不用写return,返回值就是该表达式的结果。

  • 好处:函数没有名字,不必担心函数名冲突

  • 匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

    •   >>> f = lambda x: x * x
        >>> f
        <function <lambda> at 0x101c6ef28>
        >>> f(5)
        25
      
  • 也可以把匿名函数作为返回值返回

    •   def build(x, y):
            return lambda: x * x + y * y
      
  1. 装饰器 Decorator (重要,面试官常问)
  • 装饰器是一种用于修改函数或方法行为的方式,它们以 @decorator_name 的形式使用。

    • (补充:在Python中,@ 符号通常用于装饰器(decorators)和矩阵乘法。)

    • 装饰器可以用于函数、方法或类。

    • 在代码运行期间动态增加功能的方式

    • 接受一个函数作为参数,并返回一个函数。

    •   # (下面的decorator 是一个装饰器函数,会修改 my_function 的行为。)
        
        # 1.没有@时的写法:
            def my_function():
            # 函数体
        
        my_function = decorator(my_function)
        
        # 2.简化后写法:
        @decorator
        def my_function():
        	# 函数体	
      
    • 用途:装饰器是一种灵活的工具,可用于例如添加日志、权限检查、性能测量等功能。

  • 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

  • 与第2点返回函数联动,decorator本质上就是一个返回函数的高阶函数。

  • 例如,定义一个能打印日志的decorator

    •   def log(func):
            def wrapper(*args, **kw):
                print('call %s():' % func.__name__)
                return func(*args, **kw)
            return wrapper
        # wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
      
  1. 偏函数 Partial function
  • 来自Python的functools模块

  • 当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

  • 使用偏函数后可以直接使用,不许自己专门定义特别用法的固定函数(functools.partial可以把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。)

    •   # 例1:偏函数替代了什么?
        
        # 之前:定义函数
        def int2(x, base=2):
            return int(x, base)
        
        # 之后:使用偏函数,不需要再额外定义函数
        >>> import functools
        >>> int2 = functools.partial(int, base=2)
      
    •   # 例2:使用偏函数减少代码量
        
        # 定义一个取余函数,默认和2取余;
        def mod(x,y=2):
          # 返回 True 或 False
          return x % y == 0
        
        # 假设我们要计算和3取余,如果不使用partial()函数,那么我们每次调用mod()函数时,都要写y=3
        mod(4,y=3)
        mod(6,y=3)
        
        # 使用partial()函数
        from functools import partial
        mod_3 = partial(mod,y=3)
        mod_3(4)
        mod_3(6)
        # 此段代码源自教程评论区
      
  • 小结

    • 偏函数可以简化参数操作。当函数的某个参数是我们可以提前获知的,那我们就可以将它固定住!
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值