将 Python 对象转换为迭代器
Python 中的迭代器是我们将循环遍历的那些项,或者换句话说,迭代。我们可以将任何对象更改为迭代器,甚至可以在 __iter__()
和 __next__()
方法的帮助下创建我们的迭代器。
当我们必须以迭代器的形式访问某些对象时,它很有用。我们可以使用生成器循环来做到这一点,但是这些很耗时并且会使代码变得庞大。
Python 的内置方法 __iter__()
更适合此类任务。
在 Python 中使用 __iter__()
和 __next__()
方法将对象转换为迭代器
顾名思义,迭代器会一一返回数据值。迭代器对象在 __iter__()
和 __next__()
方法的帮助下执行此操作。
__iter__()
和 __next__()
方法一起构成了迭代器协议。让我们讨论一些例子来理解迭代器协议的基本工作。
demo = ("volvo", "ferrari", "audi")
val = iter(demo)
print(next(val))
print(next(val))
print(next(val))
输出:
volvo
ferrari
audi
在这里,我们有一个包含三个值的元组。我们使用 __iter__()
方法从这个元组对象中一一获取值。
此外,__next__()
方法一个接一个地遍历这些值。我们可以不同地使用 __next__()
方法,就像这样。
demo = ("volvo", "ferrari", "audi")
val = iter(demo)
print(val.__next__())
print(val.__next__())
print(val.__next__())
输出:
volvo
ferrari
audi
现在我们也得到了相同的输出。PEP 3114 将 iterator.next()
更改为 iterator.__next__()
。我们可以将这些方法与任何可迭代对象一起使用。
这是一个使用字符串的示例。
demostr = "volvo"
val = iter(demostr)
print(next(val))
print(next(val))
print(next(val))
print(next(val))
print(next(val))
输出:
v
o
l
v
o
Python 有许多可迭代的内置容器——字符串、列表、元组。我们可以使用 __iter__()
函数从可迭代对象中创建对象。
此外,我们可以使用 __next__()
方法逐个访问对象。
语法:
iter(object_name)
iter(callable, sentinel)
在这里,object_name
指的是对象,如列表或元组,其迭代器将被创建。此外,callable
是指可调用对象,sentinel
是指给出迭代终止条件的值。
sentinel 值显示了我们正在迭代的序列的结尾。因此,如果我们在所有对象都已经被迭代时调用迭代器,我们会得到 StopIterationError
异常。
请注意,创建迭代器不会更改可迭代对象。看看这个演示 StopIterationError
的示例。
li = ['volvo', 'ferrari', 'audi']
value = li.__iter__()
print(value.__next__())
print(value.__next__())
print(value.__next__())
print(value.__next__()) #Error occurs here
输出:
volvo
ferrari
audi
StopIteration
我们甚至可以创建我们的对象或类作为迭代器。让我们创建一个迭代器,它将返回一个数字序列,从 10 开始,其中每个值将增加 2。
class GetNumbers:
def __iter__(self):
self.x = 10
return self
def __next__(self):
a = self.x
self.x += 2
return a
myclass = GetNumbers()
value = iter(myclass)
print(next(value))
print(next(value))
print(next(value))
print(next(value))
print(next(value))
输出:
10
12
14
16
18
在这里,__iter__()
方法的工作方式类似于 __init__()
方法。我们可以在 __iter__()
方法中进行初始化或操作,但我们总是返回对象。
我们可以在 __next__()
方法的帮助下执行操作。但在这种情况下,返回值应该是序列的下一个元素。
在这里,我们将 2 添加到 __next__()
方法中的每个值。
Python 中迭代器的属性
为了理解内部工作,我们应该知道迭代器的一些属性。这些如下:
- 迭代对象使用内部计数变量来保持迭代计数。
- 一旦迭代完成,我们不能再次将此迭代计数变量重新分配为 0。因此,出现
StopIteration
错误。 - 因此,我们可以说迭代计数变量只能遍历一个容器一次。
这里是文档链接,谈到了 Python 中的迭代器。
现在让我们看看迭代永远不会结束的情况。这里值得注意的一点是我们使用了 __next__()
方法一定次数。
但是如果迭代器对象永远不会耗尽呢?在这种情况下,不可能多次编写 __next__()
语句。
我们使用带有两个参数的 iter()
方法。第一个参数是可调用的,第二个参数是哨兵。
因此,当返回值与哨兵匹配时,迭代器停止。将以下代码粘贴到你的编辑器中并尝试运行它。
int()
value = iter(int, 1)
next(value)
输出:
>>> 1
1
>>> 1
1
>>> 2
2
>>> 3
3
>>>
当你运行这段代码时,你会看到迭代器永远不会停止。这是因为 int()
函数每次都返回 0
。
不管你给什么值作为输入,返回的值都不会与 sentinel 相同,这里是 1。尝试将 sentinel 的值更改为 0。
int()
value = iter(int, 0)
next(value)
输出:
StopIteration
这一次,我们在第一次运行时得到了 StopIteration
异常。
我们创建迭代器的方式,我们也可以创建无限迭代器。让我们创建一个无限迭代器,它将返回所有偶数的列表。
class Even:
def __iter__(self):
self.x = 0
return self
def __next__(self):
x = self.x
self.x += 2
return x
输出:
>>> obj = iter(Even())
>>> next(obj)
0
>>> next(obj)
2
>>> next(obj)
4
>>>
使用迭代器的最大优点是它们可以帮助我们节省资源。请注意,如果我们使用变量,将会浪费大量空间。
但是在迭代器的帮助下,我们可以得到所有偶数,而不用担心将它们存储在内存中。
要了解有关 Python 中迭代器对象的更多信息,请参阅此文档。
结论
在本文中,我们讨论了 Python 中迭代器的概念。我们讨论了 __iter__()
和 __next__()
方法的工作原理以及一些示例。
当我们想要使用无限值时,我们还看到了迭代器的使用如何提高内存效率。我们还使用迭代器协议制作了迭代器。