美文网首页Python
2019-05-22 高阶函数

2019-05-22 高阶函数

作者: 沙滩印 | 来源:发表于2019-05-22 15:35 被阅读0次

    函数本身也可以赋值给变量,即:变量可以指向函数。

    >>> f = abs
    >>> f
    <built-in function abs>
    
    >>> f = abs
    >>> f(-10)
    10
    

    这例子说明变量f现在已经指向了abs函数本身。直接调用abs()函数和调用变量f()完全相同。
    函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!
    如果把abs指向其他对象,会有什么情况发生?

    >>> abs = 10
    >>> abs(-10)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'int' object is not callable
    

    把abs指向10后,就无法通过abs(-10)调用该函数了!因为abs这个变量已经不指向求绝对值函数而是指向一个整数10!
    当然实际代码绝对不能这么写,这里是为了说明函数名也是变量。要恢复abs函数,请重启Python交互环境。

    注:由于abs函数实际上是定义在import builtins模块中的,所以要让修改abs变量的指向在其它模块也生效,要用import builtins; builtins.abs = 10。
    把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。

    def add(x, y, f):
        return f(x) + f(y)
    

    当我们调用add(-5, 6, abs)时,参数x,y和f分别接收-5,6和abs,根据函数定义,我们可以推导计算过程为:

    x = -5
    y = 6
    f = abs
    f(x) + f(y) ==> abs(-5) + abs(6) ==> 11
    return 11
    

    map/reduce

    map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
    reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

    利用map和reduce编写一个str2float函数,把字符串'123.456'转换成浮点数123.456:
    方法1:

    # -*- coding: utf-8 -*-
    from functools import reduce
    def str2float(s):
        digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
        s1,s2 = s.split('.')
        def char2num(s):
            return digits[s]
        return reduce(lambda x,y : x*10+y , map(char2num,s1)) + reduce(lambda x,y : x*10+y ,map(char2num,s2))/pow(10,len(s2))
    
    print('str2float(\'123.456\') =', str2float('123.456'))
    if abs(str2float('123.456') - 123.456) < 0.00001:
        print('测试成功!')
    else:
        print('测试失败!')
    

    结果:

    str2float('123.456') = 123.456 
    测试成功! 
    

    方法2:

    # -*- coding: utf-8 -*-
    from functools import reduce
    def str2float(s):
        index = 0
        leng = len(s)
        for i,v in enumerate(s): #enumerate 可在迭代的时候获取到下标
           if v == '.':
              index = i
        s = s[:index] + s[index+1:] #拆除小数点,然后前后拼接
        DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
        def char2num(s):
            return DIGITS[s]
        def fn(x,y):
            return x * 10 + y 
        return 0.1**(leng-1-index) * reduce(fn,map(char2num,s)) 
        #0.1**(len-1-index) 表示小数点的位数,将整体值缩小到小数点位数倍数
    

    运行结果:

    str2float('123.456') = 123.45600000000003 
    测试成功! 
    

    filter

    Python内建的filter()函数用于过滤序列。和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。
    回数是指从左向右读和从右向左读都是一样的数,例如12321,909。请利用filter()筛选出回数:

    # -*- coding: utf-8 -*-
    def is_palindrome(n):
        return str(n)[::-1] == str(n)
    
    测试:
    output = filter(is_palindrome, range(1, 1000))
    print('1~1000:', list(output))
    if list(filter(is_palindrome, range(1, 200))) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]:
        print('测试成功!')
    else:
        print('测试失败!')
    

    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]
    

    默认情况下,对字符串排序,是按照ASCII的大小比较的,由于'Z' < 'a',结果,大写字母Z会排在小写字母a的前面。
    现在,我们提出排序应该忽略大小写,按照字母序排序。实际上就是先把字符串都变成大写(或者都变成小写),再比较。

    >>> 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']
    

    假设我们用一组tuple表示学生名字和成绩:

    L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
    请用sorted()对上述列表分别按名字排序:

    # -*- coding: utf-8 -*-
    L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
    def by_name(t):
        return(t[0])
    L2 = sorted(L, key=by_name)
    print(L2)
    

    运行结果:

    [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)] 
    

    相关文章

      网友评论

        本文标题:2019-05-22 高阶函数

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