美文网首页程序员
Python干货-函数式编程之高阶函数

Python干货-函数式编程之高阶函数

作者: 东南有大树 | 来源:发表于2018-10-27 18:43 被阅读12次

    认识高阶函数

    函数与变量

    print(abs(-1))
    
    1
    

    上例中,abs() 是 python 内置函数,用来求一个数值的绝对值

    就以这个函数为例,abs() 是个函数,那 abs 是这个函数的名字,() 才定义其是一个方法,如果只输入 abs,会发生什么情况?

    abs
    
    <function abs>
    

    从输出上来看,abs 是一个方法

    也就是说,abs 是一个方法的名,它指向了该方法的内存地址

    既然这个方法有地址,同样可以将它的地址赋给一个变量

    _func = abs
    print(_func(-1))
    
    1
    

    也就是说,_func 也指出了 abs 所指向的方法地址,在其后面加上括号后,便可调用所指向的方法

    所以,函数名也是变量

    函数可以被当作参数传入函数

    那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

    定义一个简单的高阶函数:

    # 定义一个高阶函数,接收两个方法作为参数
    def get_name(f_name, l_name):
        # 打印全名
        print(f_name, l_name)
        
    # 定义f_name()函数,返回frist name
    def first_name(name):
        return name
    
    # 定义l_name()函数,返回last name
    def last_name(name):
        return name
        
    # 将first_name()与last_name当作参数传入get_name()函数中
    get_name(first_name('Jack'), last_name('Chen'))
    
    Jack Chen
    

    上例中,get_name()就是一个高阶函数

    认识其它高阶函数

    map()函数

    map()是python的内置函数,它的语法如下:

    map(func, *iterables) --> map object
    

    第一个参数是一个方法,第二个参数是一个列表(序列);map的作用是将序列iterables中的元素依次作用到函数func上,并返回一个新的序列对象

    示例:

    # 定义一个函数,返回一个数的平方
    def func_square(num):
        return num**2
    
    # 调用map()函数
    num_list = map(func_square, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    print(list(num_list))
    
    [1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    从结果上来看,序列参数中的每个元素都被作用到func_square函数中,得到一个平方值,最终返回所有数的平方

    示例:

    print(list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
    
    ['1', '2', '3', '4', '5', '6', '7', '8', '9']
    

    该例中的序列参数被str()方法都转换成了字符串格式,这也是另一种运用

    reduce()函数

    reduce()函数将一个函数作用在一个序列上,这个函数必须接收两个参数,reduce()函数会继续和序列的下一个元素做累积运算

    示例:

    # 从functolls模块中导入reduce函数
    from functools import reduce
    
    # 定义一个加法函数
    def add(x, y):
        return x+y
    
    # 调用reduce()函数
    result = reduce(add, [1, 2, 3, 4, 5])
    
    print(result)
    
    15
    

    序列[1, 2, 3, 4, 5]的每一个元素作用到add()方法上,将该函数得到的结果再与下一个元素传入add()方法中,直到结束,得到的结果就是1+2+3+4+5=15

    示例:如何将序列[1, 2, 3, 4, 5]转换成数字12345

    # 从functolls模块中导入reduce函数
    from functools import reduce
    
    # 定义一个转换函数
    def fn(x, y):
        return x * 10 + y
    
    # 调用reduce()函数
    result = reduce(fn, [1, 2, 3, 4, 5])
    
    print(result)
    
    12345
    

    这里定义了一个函数fn(),该函数可以将传入的丙个参数做十位数与个位数的运算,再将得出的结果与下一个元素做同样的处理,原来的十位数再乘10变成了百位数,个位数则成了十位数,新的y元素则成了个位数,依此类推,最后得出了结果12345

    map() 函数与 reduce() 函数的结合

    示例:将字符串转换成列表,再将该列表做累加运算

    # 从functolls模块中导入reduce函数
    from functools import reduce
    
    # 定义一个转换函数
    def fn(x, y):
        return x * 10 + y
    
    # 定义一个数字转换字符的方法
    def char_num(x):
        return int(x)
    
    # 调用reduce()函数
    result = reduce(fn, map(char_num, '12345'))
    
    print(result)
    
    12345
    

    map() 函数会将字符串 '12345'当作一个字符序列今次作用到 char_num() 方法上,最终会返回一个数字列表,这个列表又会依次作用到 fn() 函数上,得到的结果与上一个例子结果是一致的

    python提供了更加强大的函数编程,可以将多个方法封装到一个方法里,上面的例子中的两个方法就可以包装成一个方法,使用的时候也只需要调用一次即可同,如下:

    # 从functolls模块中导入reduce函数
    from functools import reduce
    
    # 顶层包装函数
    def func_all():
        # 定义一个转换函数
        def fn(x, y):
            return x * 10 + y
    
        # 定义一个数字转换字符的方法
        def char_num(x):
            return int(x)
    
        # 调用reduce()函数
        return  reduce(fn, map(char_num, '12345'))
    
    print(func_all())
    
    12345
    

    也可以使用lambda函数进行简化,如下:

    # 从functolls模块中导入reduce函数
    from functools import reduce
    
    # 定义一个数字转换字符的方法
    def char_num(x):
        return int(x)
    
    # 调用reduce()函数
    result = reduce(lambda x, y : x * 10 +y, map(char_num, '12345'))
    
    print(result)
    
    12345
    

    filter() 函数

    filter() 函数接收一个函数和一个序列作为参数,并将序列中的每一个元素都作用到传入函数上,根据该函数返回的布尔值,来决定当前元素是否保留

    示例:筛选一个序列,保留奇数

    # 奇数筛选函数
    def is_odd(x):
        return x % 2 == 1
    
    # 调用filter()函数
    result = filter(is_odd, [1, 2, 3, 4, 5])
    
    print(list(result))
    
    [1, 3, 5]
    

    示例:删除掉序列中的空字符串

    # 筛选空字符串
    def empty_str(x):
        return x.strip() != ''
    
    # 调用filter()函数
    result = filter(empty_str, ['', '2', 'a', '   '])
    
    print(list(result))
    
    ['2', 'a']
    

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

    示例:筛选质数

    质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。

    因数,或称为约数,数学名词。定义:整数a除以整数b(b≠0) 的商正好是整数而没有余数,我们就说b是a的因数。0不是0的因数。

    计算质数的一个方法是埃氏筛法,它的算法理解起来非常简单:

    首先,列出从2开始的所有自然数,构造一个序列:

    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...

    取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:

    3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...

    取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:

    5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...

    取新序列的第一个数5,然后用5把序列的5的倍数筛掉:

    7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...

    不断筛下去,就可以得到所有的素数。

    # 先构造一个从3开始的奇数序列
    def _odd_iter():
        n = 1
        while True:
            n = n + 2
            yield n  # yield返回的是一个生成器,所包含的序列将是无限的
            
    # 定义一个筛选函数,
    def _not_divisible(n):
        return lambda x: x % n > 0  # 这里将lambda匿名函数返回
    
    # 定义一个生成器函数
    def primes():
        yield 2  # 事先在生成器里返回了2
        it = _odd_iter() # 初始序列,这里都是奇数,返回的是一个生成器
        while True:
            n = next(it) # 返回序列的第一个数,之后返回下一个
            yield n
            it = filter(_not_divisible(n), it) # 构造新序列,每次将所有奇数作用于筛选函数返回的函数上
    
    # 打印100以内的素数:
    l = []
    for n in primes():
        if n < 100:
            l.append(n)
        else:
            break
    print(l)
    
    [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
    

    yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器

    当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象

    当你使用for进行迭代的时候,函数中的代码才会执行

    sorted() 函数

    sorted() 函数是 python 中内置的函数,可以对 list 进行排序

    示例:

    l = sorted([1, 4, 5, 2, 3])
    print(l)
    
    [1, 2, 3, 4, 5]
    

    此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序

    示例:按绝对值大小排序

    # 按大小排序
    l = sorted([1, -5, 3, -2, -4])
    print(l)
    
    # 按绝对值排序
    l = sorted([1, -5, 3, -2, -4], key=abs)
    print(l)
    
    [-5, -4, -2, 1, 3]
    [1, -2, 3, -4, -5]
    

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

    sorted() 也可以对字符串进行排序,示例:

    l_str = sorted(['hello', 'my', 'name', 'is', 'Jack'])
    print(l_str)
    
    ['Jack', 'hello', 'is', 'my', 'name']
    

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

    如果纯粹的想按字母进行排序,而不分大小写,则可以将所有的字母都转换成小写,再来进行排序,示例如下:

    l_str = sorted(['hello', 'my', 'name', 'is', 'Jack'], key=str.lower)
    print(l_str)
    
    ['hello', 'is', 'Jack', 'my', 'name']
    

    还可以反向排序,需要第三个参数reverse=True,示例如下:

    l_str = sorted(['hello', 'my', 'name', 'is', 'Jack'], key=str.lower, reverse=True)
    print(l_str)
    
    ['name', 'my', 'Jack', 'is', 'hello']

    相关文章

      网友评论

        本文标题:Python干货-函数式编程之高阶函数

        本文链接:https://www.haomeiwen.com/subject/pqndtqtx.html