我是Python新手,我想看看是否有一种更干净的方法来编写我的代码。下面的代码将可迭代性作为参数,它从第一个参数生成第一个值,然后从第二个参数生成第一个值,然后从最后一个参数生成第一个值;然后从第一个参数生成第二个值,因此on.If任何可迭代的值都不会产生更多的值,这个生成器不会产生更多的值。
如果我这样做了:
for i in skip('abcde','fg','hijk'):
print(i,end='')生成值'a‘、'f’、'h‘、'b’、'g‘、'i’和'c‘。我编写的代码如下(该代码起作用):
def skip(*args):
itrs = [iter(arg) for arg in args]
while itrs != []:
temp = []
for i in range(len(itrs)):
try:
yield next(itrs[i])
temp.append(itrs[i])
except StopIteration:
pass
itrs = temp是否有一种更简洁的方法来编写代码(而不使用任何外部库)?
发布于 2015-01-25 17:35:30
首先,我认为原始代码中有一个错误。代码生成afhbgicjdke而不是预期的afhbgic。我认为意图是在停止迭代块中使用return而不是pass,下面的答案是在这种假设下工作的。
让我们看看中间的for循环
for i in range(len(itrs)):
try:
yield next(itrs[i])
temp.append(itrs[i])
except StopIteration:
return不对索引进行操作,所以每个itrs[i]都可以用一个更简单的for i in iters替换为i。这给了我们
for i in itrs:
try:
yield next(i)
temp.append(i)
except StopIteration:
return现在让我们看一下while主体
while itrs != []:
temp = []
# ... the for loop that includes an append to itrs
itrs = temp这基本上为代码提供了一种在一切完成后退出的方法。但是,如果您考虑代码是如何工作的,itrs的长度只有当一个itrs到达StopIteration时才会比args短。如果那样的话,我们早就回来了!
这样,while循环就可以变成while循环和temp,并且它的使用也就可以完全满足了。
def skip(*args):
itrs = [iter(arg) for arg in args]
while True:
for i in itrs:
try:
yield next(i)
except StopIteration:
return现在我们需要说服自己,代码会在某个时候返回。这并不是太难,只要其中一个可迭代传入是有限的,即有一个结束,我们将在某个时候到达StopIteration。在每一个可迭代性都是无限的情况下,原始代码也将永远运行。所以我们在那里很好。
但还有另一个问题。如果调用skip时没有任何参数,该怎么办?这将导致我们永远不会从函数返回,因为我们没有可迭代的触发StopIteration!在原始代码中,这是通过temp为空隐式处理的。既然我们已经没有它了,我们必须明确地处理它。这给了我们最后的代码:
def skip(*args):
if len(args) == 0:
return
itrs = [iter(arg) for arg in args]
while True:
for i in itrs:
try:
yield next(i)
except StopIteration:
return有了这个
for i in skip('abcde','fg','hijk'):
print(i,end='')输出afhbgic和
for i in skip():
print(i,end='')是个圆头
另外,原始代码中的缩进是不一致的,这使得它无法运行.请确保下次发布可用代码。
发布于 2015-01-25 20:36:48
您说过不使用外部库,但是如果您可以使用Python标准库,那么您几乎可以使用cycle函数从可迭代的迭代器上使用itertools来做您想做的事情:
from itertools import cycle
def skip(*args):
return (next(i) for i in cycle(iter(arg) for arg in args))或者更简洁的Python 3版本:
from itertools import cycle
def skip(*args):
return map(next, cycle(map(iter, args)))Python 2的简化版本也是相同的:
from itertools import cycle, imap
def skip(*args):
return imap(next, cycle(imap(iter, args)))在任何情况下,您都不需要在生成器中捕获Python2中的StopIteration:抛出它会自动结束生成器并被调用方捕获。因此,即使没有itertools,您也可以这样做:
def skip(*args):
if not args:
return
iters = [iter(arg) for arg in args]
while True:
for it in iters:
yield next(it)根据@XrXrXr的评论,由于Python3.5中的cycle冒泡,使用StopIteration的解决方案将变成:
def skip(*args):
try:
yield from (next(i) for i in cycle(iter(arg) for arg in args))
except StopIteration:
returnhttps://codereview.stackexchange.com/questions/78549
复制相似问题