闻赤松之清尘兮,
愿承风乎遗则。
——《楚辞·远游》
本期文章5400字
根据之前文章的后台统计数据推算
本期预计所需阅读时间31分钟
本系列文章已加入“维权骑士”(rightknights.com)的版权保护计划
本文原创内容受到保护
map(映射)函数
Python的内置函数map是比较有用的一个高阶函数,它对数组(或我们称为iterable(可遍历对象)的类似对象)进行一些操作。
可遍历对象,和对可遍历对象进行的迭代遍历,是Python的精髓之一。可遍历对象主要包括数组、元组、字典、yield生成器(本文后续会讲到)等。对数组、元组、字典的迭代遍历,在之前的文章中均已涉及,此处不再多说;对于yield生成器所生成的对象的迭代遍历,在后文会讲到。
回到这部分的主要话题。map函数将一个函数和一个可遍历对象作为参数,并返回一个新的可遍历对象。map函数把那个作为参数的函数应用于可遍历对象的每一项,并把处理结果作为一个新的可遍历对象进行返回。
可以理解:map(映射)的意思是,把作为参数的那个函数看作一种映射关系,映射前的元素集合是传入的原可遍历对象,映射后的元素集合是map函数产生的元素的集合,这也符合数学上关于“集合”的概念:“两个非空集合A(原可遍历对象)与B(新产生的可遍历对象)间存在着对应关系f(函数),而且对于A中的每一个元素x,B中总有有唯一的一个元素y与它对应”。来看例子:
defadd_five(x):
return x + 5
nums = [11, 22, 33, 44, 55]
result = list(map(add_five, nums))
print(result)
运行结果:
>>>
[16, 27, 38, 49, 60]
>>>
同时,既然这里要求传入的是一个函数,那么我们当然可以在这里使用lambda函数。上一期文章说过,lambda函数对于较为简单的功能来说,是很方便的写法。所以对于上面这个例子来说,“+5”这种功能,我们可以使用lambda函数更轻松地实现相同的效果:
nums = [11, 22, 33, 44, 55]
result = list(map(lambdax: x+5, nums))
print(result)
运行结果:
>>>
[16, 27, 38, 49, 60]
>>>
可以看到,为了与传入的可遍历对象的类型(上例中为数组)加以对应,我们使用了list()函数将map()函数的返回结果转换成了数组。
filter(过滤器)函数
过滤器通过删除与条件不匹配(代入条件运算结果为False)的元素来过滤可遍历对象。看例子:
nums = [11, 22, 33, 44, 55]
res = list(filter(lambdax: x%2==0, nums))
print(res)
运行结果:
>>>
[22, 44]
>>>
如上例所示,就像刚才我们用map的时候一样,如果要以数组形式输出结果,则必须将结果用list()函数显式转换为数组。
测试题14.1.
填空,使代码以数组的形式输出原数组中所有小于5的元素。
nums = [1, 2, 5, 8, 3, 0, 7]
res = list( _____ (lambda x: x _____ 5, _____ ))
print(res)
点击下方空白区域查看答案
▼
filter
完整代码如下:
nums = [1, 2, 5, 8, 3, 0, 7]
res = list(filter (lambda x: x
print(res)
可以看到,由于map和filter的目标已经被规定了是一个可遍历对象,所以在map和filter的参数中,传入数组等对象的时候只需要写这些对象的名字就可以,不需要写括号(如数组的方括号,元组的圆括号等)。
generator(系列值生成器)
generator是一种可遍历对象,类似于数组或元组。
与数组和元组不同,generator不允许使用任意索引值进行索引,但我们仍然可以使用for循环进行迭代遍历generator。
我们可以使用函数和yield语句创建generator对象。来看例子:
defcountdown():
i=5
while i > 0:
yieldi
i -= 1
for i in countdown():
print(i)
运行结果:
可以这样理解:yield语句用于定义generator对象,作为函数的返回值向调用这个函数的位置提供信息。
由于yield语句一次产生一个项目,因此generator没有数组那样的内存限制。我们可以理解为,generator对象可以是无限量的。
definfinite_sevens():
while True:
yield7
for i in infinite_sevens():
print(i)
运行结果:
>>>
7
7
7
7
...
测试题14.2.难
填空。假设我们已经定义了函数is_prime,当传入is_prime的参数为质数时,返回值为True,否则返回值为False。要求使下面的代码以数组的形式输出原数组中所有小于5的元素。
_____ get_primes():
num = 2
while True:
if is_prime(num):
_____ _____
num _____ 1
点击下方空白区域查看答案
▼
def yield num+=
完整代码如下:
def get_primes():
num = 2
while True:
if is_prime(num):
yield num
num += 1
有限量的generator对象可以通过将它作为参数传递给list()函数来转换为数组。
defnumbers(x):
for i in range(x):
if i % 2 == 0:
yieldi
print(list(numbers(11)))
运行结果:
>>>
[0, 2, 4, 6, 8, 10]
>>>
使用generator对象来代替同样内容的数组或者元组等对象,可以提高程序的性能,这是延迟(按需)生成元素值的结果。从之前的内容中我们可以看出,generator并非一下子把所有元素值全部生成出来(如果那样的话也不可能出现无限量的情况),而是一个一个地生成元素值、返回元素值、生成下一个元素值、返回下一个元素值…这样的元素生成方式意味着更低的内存空间使用量。此外,由于generator中的元素是逐个生成、立刻使用的,所以在开始使用generator的元素之前,我们不需要等到所有元素都生成完,这样可以避免数组等类型在元素量很大的时候等待元素完整准备好的等待时间,而这种大量数据的准备时间恰恰是程序出现“未响应”状态的主要因素。
测试题14.3.
代码的输出结果是?
def make_word():
word = ""
for ch in "spam":
word +=ch
yield word
print(list(make_word()))
领取专属 10元无门槛券
私享最新 技术干货