Iterables在Python中的实际工作方式

Python语言最令人印象深刻的功能之一就是使用了“ for-each”循环结构,自从我开始使用Python以来,这种结构就令我敬畏。 对于初学者,这是一个简单的for循环,它打印前10个自然数:

for num in range(1, 11):
print(num)

我们还可以通过类似的方式遍历基本类型,例如列表,元组,字典字符串

numbers = [1, 2, 3, 4, 5]
record = ('Kshitij', 21, 'Loves Python')
details = {
'name': 'Kshitij',
'age': 21
}
for num in numbers:
print(num) # 1 2 3 4 5
for data in record:
print(data) # Kshitij 21 Loves Python
for key, value in details.items():
print(key, value) # age 21 name Kshitij

当一个人使用class在Python中实现很少的数据结构时,他感到渴望遍历存储在其实例中的数据。 这就是迭代器协议的用武之地。

样例实施

让我们假设我们的任务是实现标准的52张卡片组 。 一个示例实现可能看起来像这样:

关于创建Deck新实例并对其进行表示,这可以很好地工作。 但是,此实现中的一个主要难题是缺乏迭代Deck对象的能力。

>>> from cards import Deck
>>> new_deck = Deck() # New deck instantiated
>>> print(new_deck)
... # Works great
>>> for card in new_deck:
... print(card)
TypeError: 'Deck' object is not iterable

可以足够聪明地探索实例new_deck并得出结论, cards属性包含迭代所需的数据,而它实际上是一个list 。 有了这些知识,他可以按如下方法破解上述循环:

>>> for card in new_deck.cards:
... print(card)
Card(...)
..
..

这段代码很棒。 但是,最终用户必须获得有关实现的内部信息才能执行迭代。 这使我们的代码失去了数据抽象的优势,并导致了很多实现上的期望。

肯定有更好的办法!

在Raymond Hettinger的热情推动下,我寻找了一些方法来改进我的实现,以配合Python的for循环。

很快我找到了答案- 迭代器协议。

迭代器协议

为了了解协议是什么以及如何在Python中实现它,我们需要了解一些基本术语。

可迭代的
  • 您可以使用for循环遍历任何对象。
  • 可迭代的对象并不总是可索引的,它们并不总是具有长度,也不总是有限的。
  • 可以将iterable传递给iter()内置函数以为其获取迭代器。
迭代器
  • 迭代器只有一项工作:在迭代器中返回“ next”项。
  • 可以将迭代器传递给内置的next函数,以从中获取下一个项;如果没有下一个项(因为我们到达末尾),则会引发StopIteration异常。
  • 迭代器在传递给内置的iter()时返回自身。

协议书

步骤01:内置iter()的工作方式是什么?

每当解释器需要遍历对象x ,它将自动调用iter(x)iter内置函数:

  1. 检查对象是否实现__iter__方法,并调用该方法以获得迭代器。
  2. 如果未实现__iter__方法,但实现了__getitem__方法,则Python将创建一个迭代器 ,尝试从索引0开始按顺序获取项目。
  3. 如果失败,Python会引发TypeError异常,指出<classname> object is not iterable
步骤02:如何执行协议?

我将介绍两种实现迭代器协议的方法:

方法1:传统方式
  1. 创建一个表示迭代器的新类(例如DeckIterator
  2. DeckIterator中实现以下两种方法

__next__ :返回iterable中的下一项。

__iter__ :返回自身,即self

3.在类中定义要迭代其实例的__iter__方法,即Deck 该方法应返回DeckIterator的实例。

方法2:务实的方式
  1. Deck类中实现__iter__方法作为生成器函数

特征

这是实现协议后我们的对象似乎神奇地支持的所有功能的列表。

  1. 通过for循环进行迭代
  2. 与元组类似的拆包
  3. 可以用于列表推导
  4. 可以与消耗可迭代函数的内置函数(如minmax )一起使用。
>>> new_deck = Deck()
>>> # 1. Looping through a for loop
>>> for card in new_deck:
... print(card) # Works great!
>>> # 2. Unpacking similarly to tuples
>>> first_card, *rest, last_card = new_deck
>>> # 3. List Comprehensions
>>> spades = [card for card in new_deck if card.suit == 'Spades']
>>> # 4. Built-in functions
>>> max_card, min_card = max(new_deck), min(new_deck)

得到教训:

  1. Python中的迭代器与类型无关,而与协议无关,即,可以迭代实现该协议的任何类。
  2. Python 反复迭代。

我希望对Iterator协议的了解对您编写Python有所帮助。 为了提高人们对Python似乎不受欢迎的功能的认识,我在PyCon India 2017上提出了关于该主题的演讲

From: https://hackernoon.com/how-iterables-actually-work-in-python-65c36ff91c1e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值