[英]Return generator VS iterate with while until None
From two options below what is more appealing(readable code, more pythonic, efficiency , etc..) for running through iterable and if I want add more logic in the future(for example add 1 to every returned value)? 从下面的两个选项中,什么是更有吸引力的(可读代码,更多pythonic,效率等),用于遍历可迭代,并且如果将来我想添加更多逻辑(例如,对每个返回值添加1)?
One of options returns generator, the other returns next item and None
when done all iterations. 一个选项返回生成器,另一个返回下一项,所有迭代完成后返回
None
。
Is there a preferable method? 有没有更好的方法? If yes, why?
如果是,为什么? Is there limitations some method has that another don't.
是否存在某些方法没有的局限性?
class Option1():
def __init__(self):
self.current = 0
def get_next_batch(self, my_list):
if self.current == len(my_list):
self.current = 0
return None
self.current += 1
return [my_list[self.current-1]]
class Option2():
def __init__(self):
self.current = 0
def get_next_batch(self, my_list):
while self.current < len(my_list):
yield [my_list[self.current]]
self.current += 1
self.current = 0
raise StopIteration()
Usage: 用法:
o1 = Option1()
o2 = Option2()
arr = [1,2,3,4,5]
a = o1.get_next_batch(arr)
while a is not None:
print a
a = o1.get_next_batch(arr)
for item in o2.get_next_batch(arr):
print item
Output in both cases: 两种情况下的输出:
[1]
[2]
[3]
[4]
[5]
You almost certainly want to go with the second. 您几乎可以肯定要选择第二个。 Less lines, less opportunity for things to go wrong.
更少的线路,更少的出错机会。
However, seeing as you're not using current
outside the iterator I would just optimise the whole thing down to: 但是,看到您不在迭代器外部使用
current
,我只会将整个过程优化为:
def get_next_batch(my_list):
for item in my_list:
yield [item]
arr = [1,2,3,4,5]
for item in get_next_batch(arr):
print item
Side points. 旁点。 Always make your classes inherit from
object
in python 2.7, and don't raise StopIteration
to halt a generator in python -- it's deprecated behaviour that can lead to bugs. 始终使您的类从python 2.7中的
object
继承,并且不要提高StopIteration
来终止python中的生成器-不推荐使用的行为可能导致bug。 Use return
instead. 使用
return
代替。 eg. 例如。
def get_next_batch(my_list):
for item in my_list:
if item > 3:
return
yield [item]
batched = list(get_next_batch([1,2,3,4,5]))
expected = [[1], [2], [3]]
print batched == expected
You can tidy up Option1
to make it easy to use in for loops. 您可以整理
Option1
以使其易于在for循环中使用。 To do this you can make it with the iterator protocol. 为此,您可以使用迭代器协议。 That is an
__iter__
method that returns self
and a next
method to get the next item. 那是一个
__iter__
方法,它返回self
和一个next
方法来获取下一个项目。 eg. 例如。
class UsingNext(object):
def __init__(self, mylist):
self.current = 0
self.mylist = mylist
def __iter__(self):
return self
def next(self): # __next__ in python 3
if self.current >= len(self.mylist):
raise StopIteration
if self.current == 2:
self.current += 1
return "special"
item = self.mylist[self.current]
self.current += 1
return [item]
class UsingYield(object):
def __init__(self, mylist):
self.mylist = mylist
def __iter__(self):
for current, item in enumerate(self.mylist):
if current == 2:
yield "special"
continue
yield [item]
arr = range(1, 6)
# both print
# [1]
# [2]
# special
# [4]
# [5]
for item in UsingNext(arr):
print item
for item in UsingYield(arr):
print item
In my mind the generator version is cleaner, and easier to understand. 在我看来,生成器版本更干净,更易于理解。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.