繁体   English   中英

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

[英]Return generator VS iterate with while until None

从下面的两个选项中,什么是更有吸引力的(可读代码,更多pythonic,效率等),用于遍历可迭代,并且如果将来我想添加更多逻辑(例如,对每个返回值添加1)?

一个选项返回生成器,另一个返回下一项,所有迭代完成后返回None

有没有更好的方法? 如果是,为什么? 是否存在某些方法没有的局限性?

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()

用法:

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

两种情况下的输出:

[1]
[2]
[3]
[4]
[5]

您几乎可以肯定要选择第二个。 更少的线路,更少的出错机会。

但是,看到您不在迭代器外部使用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

旁点。 始终使您的类从python 2.7中的object继承,并且不要提高StopIteration来终止python中的生成器-不推荐使用的行为可能导致bug。 使用return代替。 例如。

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

您可以整理Option1以使其易于在for循环中使用。 为此,您可以使用迭代器协议。 那是一个__iter__方法,它返回self和一个next方法来获取下一个项目。 例如。

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

在我看来,生成器版本更干净,更易于理解。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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