高阶函数

函数可以接收另一个函数作为参数,称之为高阶函数。函数式编程就是指这种高度抽象的编程范式。

例如:

1
2
3
4
def add(x, y, f):
    return f(x) + f(y)

add(-5, 6, abs) # 结果为11

Python内置高阶函数

map(function, iterable, …)

map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。返回的是一个Iterator。

例如:

1
2
3
4
5
6
7
8
from collections import Iterator
def f(x):
    return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(type(r))                 # 打印r的类型
print(isinstance(r,Iterator))  # 验证r是否是Iterator。结果True
print(r)
print(list(r))

执行以上程序会输出如下结果:

1
2
3
4
<class 'map'>
True
<map object at 0x7ffb2e1f0898>
[1, 4, 9, 16, 25, 36, 49, 64, 81]

例如,数字转为字符串

1
2
3
4
5
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
m = map(str, l)
print(type(m))
print(m)
print(list(m))

执行以上程序会输出如下结果:

1
2
3
<class 'map'>
<map object at 0x7fb35d184828>
['1', '2', '3', '4', '5', '6', '7', '8', '9']

filter(function, iterable)

filter()函数用于过滤序列。接收一个函数和一个序列。filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from collections import Iterator
def f1(x):  
    if x>20:
        return True  
    else:  
        return False

l1 = [ 1, 2, 3, 42, 67, 16 ]  
f = filter(f1, l1)
print(type(f))                 # 打印f的类型
print(isinstance(f,Iterator))  # 验证f是否是Iterator。结果True
print(f)
print(list(f))

执行以上程序会输出如下结果:

1
2
3
4
<class 'filter'>
True
<filter object at 0x7f60222568d0>
[42, 67]

当然,也可以使用Iterator的next方法来迭代。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from collections import Iterator
def f1(x):  
    if x>20:
        return True  
    else:  
        return False

l1 = [ 1, 2, 3, 42, 67, 16 ]  
f = filter(f1, l1)
print(f.__next__)    # 打印迭代器对象f的next对象
print(f.__next__())  # 获取第一个成员值
print(f.__next__())  # 获取第二个成员值
print(f.__next__())  # 迭代结束

执行以上程序会输出如下结果:

1
2
3
4
5
6
7
<method-wrapper '__next__' of filter object at 0x7f349089c8d0>
42
67
Traceback (most recent call last):
  File "main.py", line 15, in <module>
    print(f.__next__())  
StopIteration

sorted(iterable, *, key=None, reverse=False)

sorted()用于对集合进行排序(这里说的集合是对可迭代对象的一个统称,他们可以是列表、字典、set、甚至是字符串,字节)。返回一个新排列好的集合。

1.默认排序
默认情况,sorted函数将按列表升序进行排序,并返回一个新列表对象,原列表保持不变,最简单的排序

例如:

1
2
3
4
5
6
7
nums = [3,4,5,2,1]
new_nums = sorted(nums)
print(type(nums))
print(type(new_nums))
print(nums is new_nums)
print(nums)
print(new_nums)

执行以上程序会输出如下结果:

1
2
3
4
5
<class 'list'>
<class 'list'>
False
[3, 4, 5, 2, 1]
[1, 2, 3, 4, 5]

2.降序排序 如果要按照降序排列,只需指定参数 reverse=True 即可

例如:

1
2
3
4
5
6
7
nums = [3,4,5,2,1]
new_nums = sorted(nums,reverse=True)
print(type(nums))
print(type(new_nums))
print(nums is new_nums)
print(nums)
print(new_nums)

执行以上程序会输出如下结果:

1
2
3
4
5
<class 'list'>
<class 'list'>
False
[3, 4, 5, 2, 1]
[5, 4, 3, 2, 1]

3.自定义规则排序
如果要按照某个特定的规则排序,则需指定参数key, key是一个函数(或其它可调用对象),例如:一个字符串构成的列表,我想按照字符串的长度来排序。len是内建函数,sorted函数在排序的时候会用len去获取每个字符串的长度来排序。

例如:

1
2
3
4
5
6
7
chars = ['Andrew', 'This', 'a', 'from', 'is', 'string', 'test']
new_chars = sorted(chars, key=len)
print(type(chars))
print(type(new_chars))
print(chars is new_chars)
print(chars)
print(new_chars)

执行以上程序会输出如下结果:

1
2
3
4
5
<class 'list'>
<class 'list'>
False
['Andrew', 'This', 'a', 'from', 'is', 'string', 'test']
['a', 'is', 'This', 'from', 'test', 'Andrew', 'string']

4.复合排序
如果是一个复合列表结构,例如:由元组构成的列表,要按照元组中的第二个元素排序,那么可以用 lambda 定义一个匿名函数,这里就是按照第二个元素的字母升序来排列的

例如:

1
2
3
4
5
6
7
stu = [('zhang', 'A'), ('li', 'D'), ('wang', 'C')]
new_stu = sorted(stu, key=lambda x: x[1])
print(type(stu))
print(type(new_stu))
print(stu is new_stu)
print(stu)
print(new_stu) #按照字母 A-C-D 的顺序排列。

执行以上程序会输出如下结果:

1
2
3
4
5
<class 'list'>
<class 'list'>
False
[('zhang', 'A'), ('li', 'D'), ('wang', 'C')]
[('zhang', 'A'), ('wang', 'C'), ('li', 'D')]

5、类的实例对象排序
如果要排序的元素是自定义类,例如Student类按照年龄来排序,则可以写成

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Student:
     def __init__(self, name, grade, age):
         self.name = name
         self.grade = grade
         self.age = age
     def __repr__(self):
         return repr((self.name, self.grade, self.age))

student_objects = [
 Student('john', 'A', 15),
 Student('jane', 'B', 12),
 Student('lily', 'A', 12),
 Student('dave', 'B', 10), ]

print(sorted(student_objects, key=lambda t:t.age))

# 打印 [('dave', 'B', 10), ('jane', 'B', 12), ('lily', 'A', 12), ('john', 'A', 15)]

6.多个值排序
和数据库的排序一样,sorted也可以根据多个字段来排序,例如我有先要根据age排序,如果age相同的则根据grade排序,则可以使用元组:

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Student:
     def __init__(self, name, grade, age):
         self.name = name
         self.grade = grade
         self.age = age
     def __repr__(self):
         return repr((self.name, self.grade, self.age))

student_objects = [
 Student('john', 'A', 15),
 Student('jane', 'B', 12),
 Student('lily', 'A', 12),
 Student('dave', 'B', 10), ]

print(sorted(student_objects, key=lambda t:(t.age, t.grade)))

# 打印 [('dave', 'B', 10), ('lily', 'A', 12), ('jane', 'B', 12), ('john', 'A', 15)]

7.不可直接比较的值排序
前面碰到的排序场景都是建立在两个元素是可以互相比较的前提下,例如数值按大小比较, 字母按ASCII顺序比较,如果遇到本身是不可比较的,需要我们自己来定义比较规则的情况如何处理呢? 举个简单的例子:

例如:

1
2
3
4
nums = [2, 1.5, 2.5, '2', '2.5']
print(sorted(nums))

TypeError: '<' not supported between instances of 'str' and 'int'

我们需要使用 functools 模块中的 cmp_to_key 来指定比较函数。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import functools
def compare(x1, x2):
    if isinstance(x1, str):
        x1 = float(x1)
    if isinstance(x2, str):
        x2 = float(x2)
    return x1 - x2
print(sorted(nums, key=functools.cmp_to_key(compare)))

# 打印 [1.5, 2, '2', 2.5, '2.5']

8.优化排序
对于集合构成的列表,有一种更高效的方法指定这个key

例如:

1
2
3
4
5
6
from operator import itemgetter

students = [('zhang', 'A'), ('li', 'D'), ('wang', 'C')]
print(sorted(students, key=itemgetter(1)))

# 打印 [('zhang', 'A'), ('wang', 'C'), ('li', 'D')]

9.高级排序
同样的,对于自定义类,也有一种更高效的方法指定key

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from operator import attrgetter
class Student:
     def __init__(self, name, grade, age):
         self.name = name
         self.grade = grade
         self.age = age
     def __repr__(self):
         return repr((self.name, self.grade, self.age))
student_objects = [
 Student('john', 'A', 15),
 Student('jane', 'B', 12),
 Student('dave', 'B', 10), ]
print(sorted(student_objects, key=attrgetter('age')))

# 打印 [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

# 如果参与排序的字段有两个怎么办,你可以这样:
print(sorted(student_objects, key=attrgetter('grade', 'age')))

# 打印 [('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

reduce

在Python3里,reduce()函数已经被从全局名字空间移除了,它现在被放置在functools模块里。reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

例如:

1
2
3
4
5
6
7
8
from functools import reduce

L=[0, 1, 2, 3, 4, 5, 6]
def f4(x,y):
    return(x+y)
r = reduce(f4, L)  #0+1+2+3+4+5+6
print(type(r))  #打印r的类型
print(r)

执行以上程序会输出如下结果:

1
2
<class 'int'>
21

reduce()还可以接收第3个可选参数,作为计算的初始值。

例如:

1
2
3
4
5
from functools import reduce

print(reduce(lambda x,y:x*y,range(1,3),5))  # 相当于(5*1*2)
print(reduce(lambda x,y:x*y,range(1,6),3))  #相当于(3*1*2*3*4*5)
print(reduce(lambda x,y:x+y,[1,2,3,4,5,6])) # 相当于(0+1+2+3+4+5+6)

执行以上程序会输出如下结果:

1
2
3
10
360
21

转载请注明本网址。