首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Python中的for循环中使用next是否安全?

在Python中的for循环中使用next是否安全?
EN

Stack Overflow用户
提问于 2018-12-13 14:37:56
回答 3查看 10.5K关注 0票数 27

考虑以下Python代码:

代码语言:javascript
运行
复制
b = [1,2,3,4,5,6,7]
a = iter(b)
for x in a :
    if (x % 2) == 0 :
        print(next(a))

它将打印3、5和7。在一个可靠的构造上迭代变量时使用next (您可以假设StopIteration异常不是问题或将被处理),还是迭代器在循环中被循环的修改违反了某些原则?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-12-13 15:00:54

在协议或理论上,没有什么问题会阻止你编写这样的代码。一个精疲力竭的迭代器it将在每次调用it.__next__时抛出StopIteration,因此for循环在技术上不会介意在循环主体中使用next/__next__调用来耗尽迭代器。

我建议不要写这样的代码,因为这个程序很难解释。如果这个场景比你在这里展示的要复杂一些,我至少要用笔和纸输入,然后计算出正在发生的事情。

事实上,您的代码片段可能甚至不像您认为的那样运行,假设您想要打印前面有偶数的每个数字。

代码语言:javascript
运行
复制
>>> b = [1, 2, 4, 7, 8]                                              
>>> a = iter(b)                                                      
>>> for x in a: 
...:    if x%2 == 0: 
...:        print(next(a, 'stop'))                                   
4
stop

为什么跳过7,尽管它前面有偶数4

代码语言:javascript
运行
复制
>>>> a = iter(b)                                                      
>>>> for x in a: 
...:     print('for loop assigned x={}'.format(x)) 
...:     if x%2 == 0: 
...:         nxt = next(a, 'stop') 
...:         print('if popped nxt={} from iterator'.format(nxt)) 
...:         print(nxt)
...:                                               
for loop assigned x=1
for loop assigned x=2
if popped nxt=4 from iterator
4
for loop assigned x=7
for loop assigned x=8
if popped nxt=stop from iterator
stop

结果表明,x = 4从未由for循环分配,因为显式next调用在迭代器循环有机会再次查看迭代器之前从迭代器中弹出该元素。

当我阅读代码时,这是我不想知道的细节。

如果您想在"(element, next_element)“对中迭代一个可迭代的(包括迭代器),请使用itertools文档中的pairwise 食谱

代码语言:javascript
运行
复制
from itertools import tee                                         

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..." 
    a, b = tee(iterable) 
    next(b, None) 
    return zip(a, b) 

演示:

代码语言:javascript
运行
复制
>>> b = [1,2,3,4,5,6,7]                                               
>>> a = iter(b)                                                       
>>>                                                                   
>>> for x, nxt in pairwise(a): # pairwise(b) also works 
...:    print(x, nxt)                                                                      
1 2
2 3
3 4
4 5
5 6
6 7

一般来说,itertools及其食谱为编写可读的迭代相关代码提供了许多强大的抽象。在more_itertools模块中可以找到更有用的帮助程序,包括pairwise的实现。

票数 25
EN

Stack Overflow用户

发布于 2018-12-13 15:01:20

这取决于您所说的“安全”指的是什么,正如其他人所评论的那样,这是可以的,但是您可以想象一些人为的情况,这些情况可能会让您感到意外,例如,请考虑下面的代码片段:

代码语言:javascript
运行
复制
b = [1,2,3,4,5,6,7]
a = iter(b)
def yield_stuff():
    for item in a:
        print(item)
        print(next(a))
    yield 1

list(yield_stuff())

在Python3.6上,它运行并输出:

代码语言:javascript
运行
复制
1
2
3
4
5
6
7

但是在Python3.7上它会引发RuntimeError: generator raised StopIteration。当然,如果您阅读佩普479,如果您正在考虑处理StopIteration,您可能永远不会遇到这种情况,但我想在for循环中调用next()的用例很少,通常有更清晰的代码重构方法。

票数 4
EN

Stack Overflow用户

发布于 2018-12-13 15:15:33

如果您修改代码以查看迭代器a发生了什么

代码语言:javascript
运行
复制
b = [1,2,3,4,5,6,7]
a = iter(b)

for x in a :
    print 'x', x
    if (x % 2) == 0 :
        print 'a', next(a)

你会看到打印出来的:

代码语言:javascript
运行
复制
x 1
x 2
a 3
x 4
a 5
x 6
a 7

这意味着当您执行next(a)时,您正在向前推进迭代器。如果您需要(或将来需要)使用迭代器a做其他事情,您将遇到问题。为了完全安全起见,请使用来自迭代工具模块的各种菜谱。例如:

代码语言:javascript
运行
复制
from itertools import tee, izip

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b) 

b = [1,2,3,4,5,6,7]
a = iter(b)
c = pairwise(a)

for x, next_x in c:
    if x % 2 == 0:
        print next_x

并不是说您在循环的任何地方都完全控制了当前迭代器元素,或者下一个迭代器元素。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53764256

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档