簡體   English   中英

python迭代器、生成器以及介於兩者之間

[英]python iterators, generators and in between

所以我得到了用於惰性求值和生成器表達式的生成器函數,也就是生成器推導式作為它的語法糖等價物。

我理解類

class Itertest1:
    def __init__(self):
        self.count = 0
        self.max_repeats = 100

    def __iter__(self):
        print("in __inter__()")
        return self

    def __next__(self):
        if self.count >= self.max_repeats:
            raise StopIteration
        self.count += 1
        print(self.count)
        return self.count

作為實現迭代器接口的一種方式,即iter ()和next ()在同一個類中。

但那是什么

class Itertest2:
    def __init__(self):
        self.data = list(range(100))

    def __iter__(self):
        print("in __inter__()")
        for i, dp in enumerate(self.data):
            print("idx:", i)
            yield dp

它在iter成員函數中使用了 yield 語句?

我還注意到在調用 iter 成員函數時

it = Itertest2().__iter__()
batch = it.__next__()

print語句只在第一次調用next ()時執行。 這是由於收益率和迭代的這種奇怪的混合嗎? 我認為這很違反直覺......

在任何函數中的任何位置都有yield語句將函數代碼包裝在(本機)生成器對象中,並用一個存根替換該函數,該存根為您提供所述生成器對象。

因此,在這里,調用__iter__將為您提供一個執行所需代碼的匿名生成器對象。

__next__的主要用例是提供一種無需依賴(本機)生成器即可編寫迭代器的方法。

__iter__的用例是區分對象和該對象上的迭代狀態。 考慮像這樣的代碼

c = some_iterable()
for a in c:
    for b in c:
        # do something with a and b

您不希望兩個交錯的迭代干擾彼此的狀態。 這就是為什么這樣的循環會脫糖成類似的東西

c = some_iterable()
_iter1 = iter(c)
try:
    while True:
        a = next(_iter1)
        _iter2 = iter(c)
        try:
            while True:
                b = next(_iter2)
                # do something with a and b
        except StopIteration:
            pass
 except StopIteration:
     pass

通常,自定義迭代器實現一個返回self的存根__iter__ ,因此iter(iter(x))等價於iter(x) 這在編寫迭代器包裝器時很重要。

可以使用單獨的迭代器類編寫與Itertest2等效的東西。

class Itertest3:
    def __init__(self):
        self.data = list(range(100))

    def __iter__(self):
        return Itertest3Iterator(self.data)


class Itertest3Iterator:
    def __init__(self, data):
        self.data = enumerate(data)

    def __iter__(self):
        return self

    def __next__(self):
        print("in __inter__()")
        i, dp = next(self.state)  # Let StopIteration exception propagate
        print("idx:", i)
        return dp

與此相比, Itertest1 ,其中的實例Itertest1本身承載的迭代周圍的狀態。 Itertest1.__iter__每次調用Itertest1.__iter__返回相同的對象( Itertest1的實例),因此它們無法獨立迭代數據。

請注意,我將print("in __iter__()")放在__next__ ,而不是__iter__ 正如您所觀察到的,在第一次調用__next__之前,生成器函數中的任何內容實際上都不會執行 生成器函數本身創建一個生成器; 它實際上並沒有開始執行其中的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM