Python 全栈 60 天精通之路

Day 21:5 个常用的高阶函数,3 个创建迭代器的函数

发布日期:2022年3月12日 18:02 阅读: 293 访问: 293

今天介绍 8 个实用的内置函数。高阶函数filter(function, iterable)  过滤器,过滤掉不满足函数 function 的元素,重新返回一个新的迭代器。这个函数大概等价于下面自定义函数 filter_self:d

今天介绍 8 个实用的内置函数。

高阶函数

filter(function, iterable)  

过滤器,过滤掉不满足函数 function 的元素,重新返回一个新的迭代器。这个函数大概等价于下面自定义函数 filter_self:

def filter_self(function,iterable):
    return iter([ item for item in iterable if function(item)])

filter_self 函数接收一个 function 作为参数,满足条件的元素才得以保留。

调用 filter_self,筛选出满足指定身高的学生。其条件是,男生身高超过 1.75,女生身高超过 1.65。

class Student():
    def __init__(self,name,sex, height):
        self.name = name
        self.sex = sex
        self.height = height

def height_condition(stu):
    if stu.sex == 'male':
        return stu.height > 1.75
    else:
        return stu.height > 1.65

students = [Student('xiaoming','male',1.74),
           Student('xiaohong','female',1.68),
           Student('xiaoli','male',1.80)]
students_satisfy = filter_self(height_condition,students)
for stu in students_satisfy:
    print(stu.name)

打印结果:

xiaohong
xiaoli

解释下 height_condition 函数,其第一个参数是可迭代对象 iterable 中的一个元素,这是值得注意的。

以上使用自定义过滤函数,下面使用 Python 内置的 filter 函数,也实现一遍学生身高筛选功能。

students_satisfy = filter(height_condition,students)
for stu in students_satisfy:
    print(stu.name)

打印结果如下,与上面使用自定义过滤函数实现的结果相同。

xiaohong
xiaoli

map(function, iterable, …)

它将 function 映射于 iterable 中的每一项,并返回一个新的迭代器。

如下,map 函数实现每个元素加 1:

In [10]: mylst = [1,3,2,4,1]
In [12]: result = map(lambda x: x+1, mylst)
In [13]: result
Out[13]: <map at 0x214b38353c8>
In [14]: list(result)
Out[14]: [2, 4, 3, 5, 2]

同时注意到,map 函数支持传入多个可迭代对象。

当传入多个可迭代对象时,输出元素个数等于较短序列长度。

如下,传入两个列表,function 就需要接受两个参数,取值分别对应第一、第二个列表中的元素。

找到同时满足第一个列表的元素为奇数,第二个列表对应位置的元素为偶数的元素。

In [63]: xy = map(lambda x,y: x%2==1 and y%2==0, [1,3,2,4,1],[3,2,1,2])

In [64]: for i in xy:
    ...:     print(i)

False
True
False
False

借助 map 函数,还能实现向量级运算。

In [65]: lst1 = [1,2,3,4,5,6]
In [66]: lst2 = [3,4,5,6,3,2]

In [68]: def vector_add(x,y):
    ...:     return list(map(lambda i,j: i+j, x,y))

In [69]: vector_add(lst1,lst2)
Out[69]: [4, 6, 8, 10, 8, 8]

同时还支持,向量长度不等的加法运算:

In [65]: lst1 = [1,2,3,4,5,6]
In [70]: lst3 = [1,2]

In [71]: vector_add(lst1,lst3)
Out[71]: [2, 4]

reduce(function, iterable[, initializer])

提到 map,就会想起 reduce,前者生成映射关系,后者实现归约。

reduce 函数位于 functools 模块中,使用前需要先导入。

In [72]: from functools import reduce

reduce 函数中第一个参数是函数 function。function 函数,参数个数必须为 2,是可迭代对象 iterable 内的连续两项。

计算过程,从左侧到右侧,依次归约,直到最终为单个值并返回。

In [73]: reduce(lambda x,y: x+y,list(range(10)))
Out[73]: 45

以上 reduce 的完整过程,参考下面的演示动画:

reversed(seq)

重新生成一个反向迭代器,对输入的序列实现反转。

In [155]: rev = reversed([1,4,2,3,1])

In [156]: for i in rev:
     ...:     print(i)
1
3
2
4
1

反转过程,动画演示如下:

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

实现对序列化对象的排序

key 参数和 reverse 参数必须为关键字参数,都可省略。

In [1]: a = [1,4,2,3,1]
In [2]: sorted(a,reverse=True)
Out[2]: [4, 3, 2, 1, 1]

如果可迭代对象的元素也是一个复合对象,如下为字典。

依据依据为字典键的值,sorted 的 key 函数就会被用到。

In [80]: a = [{'name':'xiaoming','age':20,'gender':'male'},
    ...: {'name':'xiaohong','age':18,'gender':'female'},
    ...: {'name':'xiaoli','age':19,'gender':'male'}]

In [81]: b = sorted(a,key=lambda x: x['age'],reverse=False)

In [82]: b
Out[82]:
[{'name': 'xiaohong', 'age': 18, 'gender': 'female'},
 {'name': 'xiaoli', 'age': 19, 'gender': 'male'},
 {'name': 'xiaoming', 'age': 20, 'gender': 'male'}]

排序的可视化图,如下所示:

迭代器

iter(object[, sentinel])

返回一个严格意义上的可迭代对象,其中,参数 sentinel 可有可无。

In [21]: lst = [1,3,5]
In [22]: it = iter(lst)
In [23]: it
Out[23]: <list_iterator at 0x214b3886188>

In [26]: it.__next__()
Out[26]: 1

In [27]: it.__next__()
Out[27]: 3

In [28]: it.__next__()
Out[28]: 5

In [29]: it.__next__()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-29-74e64ed6c80d> in <module>
----> 1 it.__next__()

StopIteration:

it 迭代结束后,在 __next__ 时,触发 StopIteration 异常,即迭代器已经执行到最后。

下面的 for 和 in 结合,我们都比较熟悉,iterable 为可迭代对象,依次迭代输出元素。

for ele in iterable:
    print(ele)

对象 iterable 要想支持以上这类结构,需要满足什么条件呢?

只要 iterable 对象支持可迭代协议,即自定义了 __iter__ 函数,便都能配合 for 依次迭代输出其元素。

如下,TestIter 类实现了迭代协议,__iter__ 函数。

class TestIter(object):
    def __init__(self):
        self._lst = [1,3,2,3,4,5]

     #支持迭代协议(即定义有 __iter__() 函数)   
    def __iter__(self): 
         print ("__iter__ is called!!")
         return iter(self._lst)

所以,对象 t 便能结合 for,迭代输出元素。

t = TestIter()
for e in t: # 因为实现了 __iter__ 方法,所以 t 能被迭代
    print(e)

打印结果,如下所示:

__iter__ is called!!
1
3
2
3
4
5

完整过程,动画演示:

next(iterator,[, default])

返回可迭代对象的下一个元素:

In [129]: it = iter([5,3,4,1])

In [130]: next(it)
Out[130]: 5

In [131]: next(it)
Out[131]: 3

In [132]: next(it)
Out[132]: 4

In [133]: next(it)
Out[133]: 1

当迭代到最后一个元素 1 时,再执行 next,就会抛出 StopIteration,迭代器终止运行。

In [135]: next(it)
----------------------------------------------------------------------
StopIteration                        Traceback (most recent call last)
<ipython-input-135-bc1ab118995a> in <module>
----> 1 next(it)

StopIteration:

案例:定制一个递减迭代器

编写一个迭代器,通过循环语句,对某个正整数,依次递减 1,直到 0。

实现类 Descrease,继承于 Iterator 对象,重写两个方法:

  • __iter__
  • __next__
from collections.abc import Iterator

class Decrease(Iterator):
    def __init__(self, init):
        self.init = init

    def __iter__(self):
        return self

    def __next__(self):
        while 0 < self.init:
            self.init -= 1
            return self.init
        raise StopIteration

调用递减迭代器 Decrease:

descend_iter = Decrease(6)
for i in descend_iter:
    print(i)

打印结果:

5
4
3
2
1
0

核心要点:

  • __next__ 名字不能变,实现定制的迭代逻辑
  • raise StopIteration:通过 raise 中断程序。

enumerate(iterable, start=0)  

enumerate 是很有用的一个内置函数,尤其要用到列表索引时。

它返回可枚举对象,也是一个迭代器。

In [93]: s = ["a","b","c"]

In [95]: for i ,v in enumerate(s):
    ...:     print(i,v)
    ...:
0 a
1 b
2 c

也可以手动执行 next,依次输出一个 tuple。

In [96]: enum = enumerate(s)

In [97]: next(enum)
Out[97]: (0, 'a')

In [98]: next(enum)
Out[98]: (1, 'b')

In [99]: next(enum)
Out[99]: (2, 'c')

小结

今天,与大家一起学习:

5 个 重要的高阶函数

  • filter:根据条件筛选元素
  • map:映射可迭代对象
  • reduce:归约可迭代对象
  • reversed:反转可迭代对象
  • sorted:排序可迭代对象

3 个 有用的迭代器函数

  • iter:返回一个迭代器
  • next:返回迭代器的下一项
  • enumerate:返回对象的枚举迭代器

动画对应短视频下载链接:

https://pan.baidu.com/s/1MrnrXEnl54XDYYwkZbSqSA

提取码:634k