簡體   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