python 可迭代对象 迭代器 生成器 生成器表达式 iter()

本文详细介绍了Python中的可迭代对象、迭代器、生成器和生成器表达式,包括它们的概念、特点和使用方法。重点讲解了迭代器的`__next__`和`__iter__`方法,以及生成器函数的`yield`关键字和`yield from`语法。还提到了`iter()`函数的使用,包括如何将可迭代对象转换为迭代器以及如何创建自定义迭代器。
摘要由CSDN通过智能技术生成

本文为阅读《流畅的python》14章 总结
可能其中自己有理解错误的地方,希望给大佬指正

可迭代对象
迭代器
生成器
生成器表达式
yield from
iter()

可迭代对象

可以被内置函数iter处理的对象
内置iter函数会检查对象是否实现了__iter__方法,如果实现了是就调用它,获取一个迭代器
如果没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试从索引0开始获取元素
如果以上都没有,则会抛出TypeError,‘X object is not iterable’


In [1]: s='abcdef'

In [2]: iter(s)
Out[2]: <str_iterator at 0x26631ddb978>

In [3]: c =1234

In [4]: iter(c)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-3b9b2877c4c0> in <module>
----> 1 iter(c)

TypeError: 'int' object is not iterable

所有可以看出s 字符串是可迭代对象,c 整数不是可迭代对象

可以迭代的对象就是可迭代对象,那什么是可迭代的?
继承或者实现了__getitem__方法或__iter__的对象,可以使用iter()测试

从 Python 3.4 开始,检查对象 x 能否迭代,最准确的方法是:调用 iter(x) 函数,如果不可迭代,再处理 TypeError 异常。这比使用 isinstance(x,abc.Iterable) 更准确,因为 iter(x) 函数会考虑到遗留的__getitem__ 方法,而 abc.Iterable 类则不考虑。
使用 iter 内置函数可以获取迭代器的对象。如果对象实现了能返回迭代器的__iter__ 方法,那么对象就是可迭代的。序列都可以迭代;实现了__getitem__ 方法,而且其参数是从零开始的索引,这种对象也可以迭代
(《流畅的python》 )

迭代器

Python从可迭代对象中获取迭代器

In [8]: s='abcd'

In [9]: for char in s:
   ...:     print(char)
a
b
c
d


In [18]: it = iter(s)   # 可迭代对象构造迭代器

In [19]: while True:
    ...:     try:
    ...:         print(next(it))  # 不断的饰演那个next函数,获取下一个字符
    ...:     except StopIteration:  # 如果没有字符了,调用next(it) 或抛出StopIteration异常
    ...:         break
a
b
c
d
In [20]: it
Out[20]: <str_iterator at 0x26631e91da0>

In [21]: next(it)    # 此时已经没有了,在使用next(it)会抛出异常
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-21-bc1ab118995a> in <module>
----> 1 next(it)

StopIteration: 

标准的迭代器有两个方法(缺一不可):
__ next __ :返回下一个可用元素·,没有元素会抛出StopIteration异常
__ iter__:返回self,以便在应该使用可迭代对象的地方使用迭代器,例如for循环中

因为迭代器只需 __ next__ 和 __ iter__ 两个方法,所以除了调用 next() 方法,以及捕获 StopIteration 异常之外,没有办法检查是否还有遗留的元素。此外,也没有办法“还原”迭代器。如果想再次迭代,那就要调用 iter(…),传入之前构建迭代器的可迭代对象。传入迭代器本身没用,因为前面说过 Iterator. __ iter__ 方法的实现方式是返回实例本身,所以传入迭代器无法还原已经耗尽的迭代器。
可迭代的对象一定不能是自身的迭代器。也就是说,可迭代的对象必须实现 __ iter__ 方法,但不能实现 __ next__ 方法。
另一方面,迭代器应该一直可以迭代。迭代器的 __ iter__ 方法应该返回自身。

生成器

普通的函数与生成器函数在句法上唯一的区别是,在后者的定义体中有 yield关键字。
只要 Python 函数中包含关键字 yield,该函数就是生成器函数。

In [3]: def gen():
   ...:     yield 1 
   ...:     yield 2 
   ...:     yield 3

In [4]: gen()
Out[4]: <generator object gen at 0x000001D53835FB48>    # 返回一个生成器对象

In [5]: for x in gen():
   ...:     print(x)
1
2
3

In [6]: g =gen()

In [7]: next(g)
Out[7]: 1

In [8]: next(g)
Out[8]: 2

In [9]: next(g)
Out[9]: 3

In [10]: next(g)    # 生成器函数的定义体执行完毕后,生成器对象会抛出 StopIteration 异常。
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-10-e734f8aca5ac> in <module>
----> 1 next(g)

StopIteration:

>>> def gen_1():
...     print('start')
...     yield 'A'
...     print('continue')
...     yield 'B'
...     print('end')
...

>>> for c in gen_1():
...     print(c)
...
start
A
continue
B
end
>>> g = gen_1()
>>> next(g)  # 会打印 'start',然后停在第一个 yield 语句,生成值 'A'。
start
'A'
>>> next(g)
continue
'B'
>>> next(g)  # 打印完end 之后到达函数末尾,生成器抛出StopIteration异常
end
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

生成器表达式

和列表推导式样子相似

In [1]: def gen_1():
   ...: ...     print('start')
   ...: ...     yield 'A'
   ...: ...     print('continue')
   ...: ...     yield 'B'
   ...: ...     print('end')
   ...:

In [2]: res1 = [x*3 for x in gen_1()]   # 列表推导式
start
continue
end

In [3]: res1
Out[3]: ['AAA', 'BBB']

In [4]: res2 = (x*3 for x in gen_1())  # 生成器推导式

In [5]: res2
Out[5]: <generator object <genexpr> at 0x00000156DA665F68>

In [6]: for x in res2:
   ...:     print(x)
   ...:
start
AAA
continue
BBB
end

yield from

python3.3 新增yield from

>>> def chain(*iterables):
... 	for it in iterables:
... 		for i in it:
... 			yield i
...
>>> s = 'ABC'
>>> t = tuple(range(3))
>>> list(chain(s, t))
['A', 'B', 'C', 0, 1, 2]


######################################

>>> def chain(*iterables):
... 	for i in iterables:
... 		yield from i     # yield from i 完全代替了内层的 for 循环。
...
>>> list(chain(s, t))
['A', 'B', 'C', 0, 1, 2]

iter() 函数

前面说使用iter(x)是可迭代对象变成迭代器
iter函数还可以出入两个参数,使常规的函数或任何可调用的对象创建迭代器,第一个参数必须是可调用的对象,用于不断调用(没
有参数),产出各个值;第二个值是哨符,这是个标记值,当可调用的对象返回这个值时,触发迭代器抛出 StopIteration 异常,而不产出哨符。

In [8]: from random import randint

In [9]: def d():
   ...:     return randint(1,6)
   ...:

In [10]: d_iter = iter(d,1)  # 返回一个 callable_iterator 对象。

In [11]: for roll in d_iter:
    ...:     print(roll)
    ...:
2
6
5
3
3    # 不会打印 1,因为 1 是哨符
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值