Python Next 函数 :从迭代器中读取数据
next() 函数在使用迭代器时很有用,它是 Python 开发人员必须知道的。
Python next() 函数将迭代器作为第一个参数,并将默认值作为可选参数。每次调用 next() 时,它都会返回迭代器中的下一项,直到没有剩余项为止。此时,下一个函数返回一个默认值(如果传递给它)或引发 StopIterarion 异常。
这里,您将了解在什么情况下可以将 next() 函数用作 Python 程序的一部分。
让我们开始吧!
Python 中的 next() 做什么?
Python next 函数有两个参数,第一个是迭代器,它是强制性的。第二个是默认值,它是可选的。
next(iterator[, default_value])
每次将迭代器传递给下一个函数时,都会返回迭代器中的下一项。
例如,让我们定义一个Python 列表,然后使用 iter() 函数创建一个迭代器。
>>> numbers = [1, 2, 3, 4]
>>> numbers_iterator = iter([1, 2, 3, 4])
在测试下一个函数之前,让我们看看 Python 解释器为列表返回的类型和与列表关联的迭代器返回的类型的区别。
>>> print(type(numbers))
<class 'list'>
>>> print(type(numbers_iterator))
<class 'list_iterator'>
现在让我们看看当我们调用 next 函数并将迭代器传递给它时我们得到了什么:
>>> next(numbers_iterator)
1
如果我们多次调用 next 函数直到迭代器没有任何剩余项,就会发生以下情况。
>>> next(numbers_iterator)
2
>>> next(numbers_iterator)
3
>>> next(numbers_iterator)
4
>>> next(numbers_iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
一旦迭代器中没有更多项,Python 解释器就会引发StopIteration 异常。
如何从 Python next 函数返回默认值
如果您不希望 Python 在到达迭代器末尾时引发 StopIteration 异常,您还可以将可选的默认值传递给下一个函数。
让我们采用之前使用过的相同列表,但这次我们将向下一个函数传递一个默认值。
>>> next(numbers_iterator, 'No more items left')
1
>>> next(numbers_iterator, 'No more items left')
2
>>> next(numbers_iterator, 'No more items left')
3
>>> next(numbers_iterator, 'No more items left')
4
>>> next(numbers_iterator, 'No more items left')
'No more items left'
正如您所看到的,当到达迭代器的末尾时,我们不再返回异常,而是返回作为可选值传递给下一个函数的默认字符串。
如果您想在到达迭代器末尾时轻松地以编程方式进行验证,则另一种选择可能是将 None 作为默认值返回。
>>> while True:
... next_value = next(numbers_iterator, None)
... if next_value:
... print(next_value)
... else:
... break
...
1
2
3
4
>>>
Next 函数与 __next__ 方法有什么关系?
一些 Python 对象提供了一个名为__next__的方法。
你知道__next__方法和next()函数有什么区别吗?
当您调用 next() 函数并将迭代器传递给它时,将调用迭代器对象的 __next__ 方法。
我想知道我们是否可以直接调用迭代器的 __next__ 方法并得到相同的结果:
>>> numbers = [1, 2, 3, 4]
>>> numbers_iterator = iter([1, 2, 3, 4])
>>> numbers_iterator.__next__()
1
>>> numbers_iterator.__next__()
2
>>> numbers_iterator.__next__()
3
>>> numbers_iterator.__next__()
4
>>> numbers_iterator.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
我们可以!
因此 __next__ 方法的行为与 next() 函数相同。
为了让您更深入地了解其工作原理,让我们将列表传递给 next() 函数,而不是将迭代器传递给它。
>>> numbers = [1, 2, 3, 4]
>>> next(numbers)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
Python 解释器会引发 TypeError 异常,因为列表不是迭代器并且它没有实现 __next__ 方法。
>>> numbers.__next__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__next__'
如您所见,列表没有任何名为 __next__ 的属性,因为此方法未在列表中实现。
如果我们对列表迭代器进行同样的检查,我们将获得有关其 __next__ 方法的详细信息。
>>> numbers_iterator = iter([1, 2, 3, 4])
>>> numbers_iterator.__next__
<method-wrapper '__next__' of list_iterator object at 0x7fb058255970>
这说明了为什么 next() 函数可以应用于迭代器而不是像列表这样的可迭代对象。
Python Next 函数和生成器表达式
next() 函数也可以与Python 生成器一起使用。
让我们拿我们的数字列表并创建一个生成器表达式来将列表中的每个数字加倍:
>>> numbers = [1, 2, 3, 4]
>>> numbers_generator = (2*number for number in numbers)
>>> print(type(numbers_generator))
<class 'generator'>
现在我们将这个生成器传递给 next() 函数,看看它返回什么:
>>> next(numbers_generator)
2
>>> next(numbers_generator)
4
>>> next(numbers_generator)
6
>>> next(numbers_generator)
8
>>> next(numbers_generator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
我们从生成器中取回我们期望的值,当 Python 解释器到达生成器的末尾时,会引发 StopIteration 异常。
正如我们之前对迭代器所做的那样,我们可以确认生成器也实现了 __next__ 方法,该方法在生成器传递给 next() 函数时调用:
>>> numbers_generator.__next__
<method-wrapper '__next__' of generator object at 0x7fb0581f9430>
在 Python 中,每个生成器都是一个迭代器。它们都实现了 __next__ 方法。
使用 next 获取匹配条件的可迭代对象中的第一项
假设您有一个可迭代对象,例如一个元组,并且您想获取可迭代对象中与特定条件匹配的第一个项目。
第一种方法是使用for 循环
例如,给定以下元组,我想知道大于 10 的第一项:
numbers = (3, 5, 9, 11, 13)
使用 for 循环,我们将执行以下操作:
>>> for number in numbers:
... if number > 10:
... print(number)
... break
...
11
另一种选择是将 next() 函数与生成器表达式一起使用。
>>> next(number for number in numbers if number > 10)
11
如果我们的条件与生成器中的任何项目都不匹配怎么办?
>>> next(number for number in numbers if number > 20)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
在这种情况下,会引发 StopIteration 异常。
正如我们在上面的一节中看到的,我们还可以将默认值传递给 next() 函数以避免此异常。
让我们这样做
>>> next((number for number in numbers if number > 20), 'No item found')
'No item found'
请注意,next() 函数传递的第一个参数是生成器,第二个参数是默认值。
应用于具有 Lambda 条件的生成器的 Python next 函数
在前面的代码中,我们使用了 next() 函数和一个生成器。我们也可以使用lambda 函数作为条件。
给定我们之前使用过的相同元组,让我们使用 lambda 编写生成器表达式:
>>> numbers = (3, 5, 9, 11, 13)
>>> next(number for number in numbers if number > 10)
注意 if 条件的写入方式是如何变化的:
>>> condition = lambda x: x > 10
>>> next(number for number in numbers if condition(number))
11
这允许使 if 条件更通用。
For 循环与下一个函数的性能
使用 Python next() 函数,我们可以复制 for 循环的相同行为。
我想知道这两种方法中哪一种最快。
让我们使用 Python range 函数创建一个包含 100,000 个项目的列表。
numbers = list(range(100000))
我们将捕获每个实现的开始时间和结束时间,以查看每个实现的执行需要多长时间。
For循环
import datetime
numbers = list(range(1,100001))
start_time = datetime.datetime.now()
for number in numbers:
print(number)
end_time = datetime.datetime.now()
print("Execution time: {}".format(end_time - start_time))
Execution time: 0:00:00.163049
接下来使用迭代器
import datetime
numbers = iter(range(1,100001))
start_time = datetime.datetime.now()
while True:
next_value = next(numbers, None)
if next_value:
print(next_value)
else:
break
end_time = datetime.datetime.now()
print("Execution time: {}".format(end_time - start_time))
Execution time: 0:00:00.177238
for 循环比使用迭代器的 next() 函数快。
- 点赞
- 收藏
- 关注作者
评论(0)