zoukankan      html  css  js  c++  java
  • Python的高阶函数小结

    一. 高阶函数定义

    简而言之,Python的高阶函数就是指一个函数作为参数传递给另外一个函数的用法

    举一个最简单的高阶函数来说明:

    >>> def add(x,y,f):
        return f(x) + f(y)
    
    >>> add(1,-2,abs)
    3

    可能会有同学问,直接return abs(x) + abs(y)不就完了么,何必这么麻烦。

    我的理解是把函数作为参数传递,能够使得编码涉及上更具有灵活性,比如我们可以根据某些变量的不同,传入不同的函数进去,这样能使得代码更简洁更好懂;不需要再重新写一大堆代码。

    举个例子

    >>> def area_circle(x):
        return 3.14*x*x
    
    >>> def area_square(x):
        return x*x
    
    >>> def area(x,p):
        return p(x)
    
    >>> area(2,area_circle)
    12.56
    >>> area(2,area_square)
    4

    在这个例子中,如果有了新的多边形(比如梯形等),我们只需要添加新的多边形的计算函数就可以,而函数def area永远都不需要变。配合dict,能使得代码更加的优雅。

    >>> area_calculation={'circle':area_circle, 'square':area_square}
    >>> area_type = 'circle'
    >>> area(2,area_calculation[area_type])
    12.56

    二. 几个比较有用的高阶函数 map/reduce, filter, sorted

     map/reduce: 

        map/reduce的概念大家应该不是第一次接触,这个概念用的最广的地方应该就是分布式计算:将计算任务拆分给多个slave计算机,然后将计算结果汇总整合。其实说白了,map/reduce的概念的核心就在于:map是将任务拆分,然后将拆分后的任务分别计算。Reduce是将map得到的各个计算结果进行汇总。只要理解了这一层,但凡涉及到map/reduce的概念都可以迎刃而解。

    • map()函数:接收两个参数,一个是函数,一个是可迭代对象 Iterable Object(关于可迭代对象Iterable Object和迭代器Iterator的概念请参考我的上一篇文章,讲得很清楚)。map()函数将传入的函数依次作用于可迭代对象的每个元素,并把结果作为Iterator返回。

    下面举个例子:

    >>> def f(x):
        return x*x
    >>> r = map(f,[1,2,3,4])
    
    #对于Iterator,我们有三种方式可以访问到元素:
    
    #方式一:用next()函数访问
    >>> next(r)
    1
    >>> next(r)
    4
    >>> next(r)
    9
    >>> next(r)
    16
    >>> next(r)
    Traceback (most recent call last):
      File "<pyshell#146>", line 1, in <module>
        next(r)
    StopIteration
    
    #方式二:利用for循环访问
    >>> r = map(f,[1,2,3,4])
    >>> for i in r:
        print(i)
    
        
    1
    4
    9
    16
    
    #方式三: 转换为list列表
    >>> r = map(f,[1,2,3,4])
    >>> list(r)
    [1, 4, 9, 16]
    • Reduce函数:同样的接收两个参数,一个是函数,一个是可迭代对象 Iterable Object(eg: list列表)。reduce中的函数必须也要接收2个参数,执行时把前一个结果继续和序列的下一个元素做累积计算,其效果就是:
    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

    举一个序列成数的例子(把序列[1,3,5,7,9变成13579])

    >>> from functools import reduce
    >>> def fn(x, y):
    ...     return x * 10 + y
    ...
    >>> reduce(fn, [1, 3, 5, 7, 9])
    13579
    • Map/Reduce常常一起配合使用,下面的例子是一个用Map/Reduce把str转换为int的函数:
    from functools import reduce
    
    DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
    
    def str2int(s):
        def fn(x, y):
            return x * 10 + y
        def char2num(s):
            return DIGITS[s]
        return reduce(fn, map(char2num, s))

    Filter:

        和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

    例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

    >>> def is_odd(n):
        return n % 2 == 1
    
    >>> list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
    [1, 5, 9, 15]

    注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

    Sorted:

        排序是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。

    Python内置的sorted()函数就可以对list进行排序:

    >>> sorted([36, 5, -12, 9, -21])
    [-21, -12, 5, 9, 36]

    此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

    >>> sorted([36, 5, -12, 9, -21], key=abs)
    [5, 9, -12, -21, 36]

    key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。

    我们再看一个字符串排序的例子:

    >>> sorted(['bob', 'about', 'Zoo', 'Credit'])
    ['Credit', 'Zoo', 'about', 'bob']

    默认情况下,对字符串排序,是按照ASCII的大小比较的,由于'Z' < 'a',结果,大写字母Z会排在小写字母a的前面。

    现在,我们提出排序应该忽略大小写,按照字母序排序。要实现这个算法,不必对现有代码大加改动,只要我们能用一个key函数把字符串映射为忽略大小写排序即可。忽略大小写来比较两个字符串,实际上就是先把字符串都变成大写(或者都变成小写),再比较。

    这样,我们给sorted传入key函数,即可实现忽略大小写的排序:

    >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
    ['about', 'bob', 'Credit', 'Zoo']

    要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True

    >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
    ['Zoo', 'Credit', 'bob', 'about']

    从上述例子可以看出,高阶函数的抽象能力是非常强大的,而且,核心代码可以保持得非常简洁。

    参考链接: 廖雪峰Python教程--高阶函数

  • 相关阅读:
    移动端-纯css隐藏滚动条解决方案
    阻止点击穿透
    JS的防抖与节流
    go 自动安装项目依赖包
    git 修改远程仓库
    git 基础命令
    go 包govalidator
    go email
    windows下Redis的安装和使用
    go xorm,负载均衡
  • 原文地址:https://www.cnblogs.com/ArsenalfanInECNU/p/9620931.html
Copyright © 2011-2022 走看看