简体   繁体   English

返回生成器VS进行迭代,直到无

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM