【人生苦短,我学 Python】(15)迭代器、生成器


Python 所有文章传送门
【Python】所有文章传送门

简述 / 前言

大多数容器对象都可以使用 for 语句。而迭代器的使用非常普遍,并使得 Python 成为一个统一的整体。在幕后,for 语句会在容器对象上调用 iter()。 该函数返回一个定义了 __next__() 方法的迭代器对象,此方法将逐一访问容器中的元素。 当元素用尽时,__next__() 将引发 StopIteration 异常来通知终止 for 循环。

1. 迭代器

实现了 __next()__ 的对象是迭代器,可以使用内置函数 next(),调用迭代器的 __next__() 方法,依次返回下一个项目值。

迭代器对象必须实现两个方法:__iter__()__next()____iter__() 用于返回对象本身,__next()__ 用于返回下一元素。

比如下述代码:

>>> s = 'abcde'
>>> it = iter(s)
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
'd'
>>> next(it)
'e'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

看一个官方写的例子:

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

rev = Reverse('spam')
iter(rev)
for char in rev:
    print(char)

其输出如下:

m
a
p
s

比如我们再实现一个由迭代器生成的不大于100的斐波拉契数列:

class Fib:
    def __init__(self):
        self.l, self.r = 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        self.l, self.r = self.r, self.l + self.r
        return self.l   # f(n) = f(n-1) + f(n-2)

fibs = Fib()
for f in fibs:
    if f <= 100:
        print(f, end=', ')
    else:
        break

其输出如下:

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 

2. 生成器

生成器函数使用 yield 语句返回一个值,然后保存当前函数整个执行状态,等待下一次调用。每次在生成器上调用 next() 时,它会从上次离开的位置恢复执行(它会记住上次执行语句时的所有数据值)。除了会自动创建方法和保存程序状态,当生成器终结时,它们还会自动引发 StopIteration

看一个官方的例子:

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

for char in reverse('spam'):
    print(char)

其输出如下:

m
a
p
s

第二个例子是生成数字0~9,用于自增函数,代码如下:

# !/usr/bin/env python3
# _*_ coding: utf-8 _*_

def CSDN(n):
    for i in range(n):
        yield i

# 方法一
for t in CSDN(10):
    print(t, end=', ')

# 方法二
print()
f = CSDN(10)
it = iter(f)
for i in range(10):
    print(next(it), end=', ')

其输出如下:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 

又比如利用生成器输出不大于100的斐波拉契数列:

def Fib():
    a, b = 0, 1
    while 1:
        a, b = b, a + b
        yield a  # f(n)=f(n-1)+f(n-2)

fibs = Fib()
for f in fibs:
    if f <= 100:
        print(f, end=', ')
    else:
        break

其输出如下:

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 

2.1 生成器表达式

与其相关的一个是生成器表达式。某些简单的生成器可以写成简洁的表达式代码,所用语法类似列表推导式,但外层为圆括号而非方括号。

比如:

>>> sum(i*i for i in range(10))
285
>>> data = 'spam'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['m', 'a', 'p', 's']

3. 常用的迭代器

3.1 enumerate 迭代器

这是一个可用于枚举可迭代对象中元素的迭代器,它会以 (计数, 元素) 的形式返回:

celebrities = ['陈凯歌', '徐克', '林超贤', '吴京#伍千里', '易烊千玺#伍万里', '段奕宏#谈子为', '朱亚文#梅生', '李晨#余从戎', '胡军#雷公', '韩东君#平河', '张涵予#宋时轮', '黄轩#毛岸英']
len_c = len(celebrities)
for num, name in enumerate(celebrities):
    print(f'{num+1}/{len_c}: {name}')

其输出如下:

1/12: 陈凯歌
2/12: 徐克
3/12: 林超贤
4/12: 吴京#伍千里
5/12: 易烊千玺#伍万里
6/12: 段奕宏#谈子为
7/12: 朱亚文#梅生
8/12: 李晨#余从戎
9/12: 胡军#雷公
10/12: 韩东君#平河
11/12: 张涵予#宋时轮
12/12: 黄轩#毛岸英

3.2 filter 迭代器

filter 是可迭代对象,使用指定函数处理可迭代对象的每个元素,函数返回 bool 类型的值。若结果为 True,则返回该元素。如果结果为 None,则返回元素为 True 的元素。

这个迭代器可以用来过滤特定值,比如去除下列列表中的空值:

  • 1 删除空内容(方法一)

    celebrities = ['', '陈凯歌', '', '徐克', '林超贤', '', '', '吴京#伍千里', '易烊千玺#伍万里', '段奕宏#谈子为', '', '朱亚文#梅生', '', '李晨#余从戎', '胡军#雷公', '韩东君#平河', '', '', '张涵予#宋时轮', '', '黄轩#毛岸英']
    
    print(list(filter(None, celebrities)))
    

    输出:

    ['陈凯歌', '徐克', '林超贤', '吴京#伍千里', '易烊千玺#伍万里', '段奕宏#谈子为', '朱亚文#梅生', '李晨#余从戎', '胡军#雷公', '韩东君#平河', '张涵予#宋时轮', '黄轩#毛岸英']
    
  • 2 删除空内容(方法二)
    需要配合 lambda 表达式一起使用!

    celebrities = ['', '陈凯歌', '', '徐克', '林超贤', '', '', '吴京#伍千里', '易烊千玺#伍万里', '段奕宏#谈子为', '', '朱亚文#梅生', '', '李晨#余从戎', '胡军#雷公', '韩东君#平河', '', '', '张涵予#宋时轮', '', '黄轩#毛岸英']
    
    print(list(filter(lambda x: x != '', celebrities)))
    

    输出:

    ['陈凯歌', '徐克', '林超贤', '吴京#伍千里', '易烊千玺#伍万里', '段奕宏#谈子为', '朱亚文#梅生', '李晨#余从戎', '胡军#雷公', '韩东君#平河', '张涵予#宋时轮', '黄轩#毛岸英']
    

具体有关的删除操作可见我之前写的一篇文章:python 一次性删除列表(list)的空白元素(空内容) 或者 一次性删除列表(list)中的指定元素 - 小邓在森林

3.3 map 迭代器

使用指定函数处理可迭代对象的每个元素。示例代码如下:

>>> list(map(abs, [-1, 100, 0, -56]))
[1, 100, 0, 56]

3.4 zip 迭代器

它可以拼接多个可迭代对象的元素。示例代码如下:

>>> list(zip([1, 2, 3], 'abc', range(3)))
[(1, 'a', 0), (2, 'b', 1), (3, 'c', 2)]
>>> list(zip([1, 2, 3], 'abc', range(30)))		# 多出的元素不会被拼接
[(1, 'a', 0), (2, 'b', 1), (3, 'c', 2)]
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的迭代器生成器是一种基于惰性计算的概念,它们可以有效地处理大量的数据或者无限序列。下面我将分别介绍迭代器生成器迭代器(Iterator)是一个实现了迭代协议(Iterator Protocol)的对象。通过调用内置函数 `iter()` 可以将可迭代对象转换为迭代器迭代器对象可以使用内置函数 `next()` 来逐个访问数据元素,直到没有更多的元素可供访问时,会引发 `StopIteration` 异常。例如,可以使用迭代器来遍历列表、元组、集合等容器类型的数据。 生成器(Generator)则是一种特殊的迭代器。它不需要显式地实现迭代协议,而是通过函数中的 `yield` 关键字来实现惰性计算。生成器函数在每次调用时返回一个值,并在下一次调用时从上一次离开的位置继续执行。这样可以节省大量的内存空间,并且提高程序的效率。生成器函数定义时使用 `def` 关键字,并包含至少一个 `yield` 关键字。 下面是一个简单的示例代码,演示了如何使用迭代器生成器: ```python # 使用迭代器遍历列表 my_list = [1, 2, 3, 4, 5] my_iter = iter(my_list) while True: try: item = next(my_iter) print(item) except StopIteration: break # 使用生成器生成斐波那契数列 def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b fib = fibonacci() for i in range(10): print(next(fib)) ``` 希望以上解释能够帮助你理解迭代器生成器的概念。如果有任何进一步的问题,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值