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)?
One of options returns generator, the other returns next item and None
when done all iterations.
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:
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. Use return
instead. 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. 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. 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.