簡體   English   中英

發電機的python發電機?

[英]python generator of generators?

我寫了一個讀取txt文件的類。 該文件由非空行塊組成(讓我們稱之為“部分”),由空行分隔:

line1.1
line1.2
line1.3

line2.1
line2.2

我的第一個實現是讀取整個文件並返回列表列表,這是一個列表列表,其中每個部分都是一個行列表。 這顯然是非常可怕的記憶。

所以我重新將它作為列表生成器實現,即在每個循環中,我的類將內存中的整個部分作為列表讀取並生成它。

這樣更好,但在大型部分的情況下仍然存在問題。 所以我想知道我是否可以重新實現它作為發電機的發電機? 問題是這個類非常通用,它應該能夠滿足這兩個用例:

  1. 讀取一個非常大的文件,包含非常大的部分,並只循環一次。 發電機的發電機是完美的。
  2. 將一個小文件讀入內存,以便多次循環。 列表生成器工作正常,因為用戶可以只調用

    列表(MyClass的(file_handle))

但是,生成器的生成器在情況2中不起作用,因為內部對象不會轉換為列表。

有沒有比實現一個顯式的to_list()方法更優雅的東西,它會將生成器的生成器轉換為列表列表?

Python 2:

map(list, generator_of_generators)

Python 3:

list(map(list, generator_of_generators))

或兩者:

[list(gen) for gen in generator_of_generators]

由於生成的對象是generator functions ,而不僅僅是生成器,您需要這樣做

[list(gen()) for gen in generator_of_generator_functions]

如果這不起作用,我不知道你在問什么。 另外,為什么它會返回發電機功能而不是發電機本身?


因為在評論中你說你想避免list(generator_of_generator_functions)神秘地崩潰,這取決於你真正想要的。

  • 這是不可能覆蓋的行為list中這樣說:要么你儲存子的發電機元件或不

  • 如果你確實遇到了崩潰,我建議每次主發電機迭代時用主發電機回路耗盡子發電機。 這是標准做法,正是itertools.groupby所做的,stdlib生成器生成器。

例如。

def metagen():
    def innergen():
        yield 1
        yield 2
        yield 3

    for i in range(3):
        r = innergen()
        yield r

        for _ in r: pass
  • 或者使用黑暗的,秘密的黑客方法,我將在mo'(我需要寫它),但不要這樣做!

正如所承諾的,黑客攻擊(對於Python 3,這次是'回合'):

from collections import UserList
from functools import partial


def objectitemcaller(key):
    def inner(*args, **kwargs):
        try:
            return getattr(object, key)(*args, **kwargs)
        except AttributeError:
            return NotImplemented
    return inner


class Listable(UserList):
    def __init__(self, iterator):
        self.iterator = iterator
        self.iterated = False

    def __iter__(self):
        return self

    def __next__(self):
        self.iterated = True
        return next(self.iterator)

    def _to_list_hack(self):
        self.data = list(self)
        del self.iterated
        del self.iterator
        self.__class__ = UserList

for key in UserList.__dict__.keys() - Listable.__dict__.keys():
    if key not in ["__class__", "__dict__", "__module__", "__subclasshook__"]:
        setattr(Listable, key, objectitemcaller(key))


def metagen():
    def innergen():
        yield 1
        yield 2
        yield 3

    for i in range(3):
        r = Listable(innergen())
        yield r

        if not r.iterated:
            r._to_list_hack()

        else:
            for item in r: pass

for item in metagen():
    print(item)
    print(list(item))
#>>> <Listable object at 0x7f46e4a4b850>
#>>> [1, 2, 3]
#>>> <Listable object at 0x7f46e4a4b950>
#>>> [1, 2, 3]
#>>> <Listable object at 0x7f46e4a4b990>
#>>> [1, 2, 3]

list(metagen())
#>>> [[1, 2, 3], [1, 2, 3], [1, 2, 3]]

這太糟糕了,我甚至不想解釋它。

關鍵是你有一個可以檢測它是否已被迭代的包裝器,如果沒有你運行_to_list_hack ,我不_to_list_hack ,改變了__class__屬性。

由於布局存在沖突,我們必須使用UserList類並為其所有方法設置陰影,這只是另一層crud。

基本上,請不要使用此hack。 不過,你可以像幽默一樣享受它。

一種相當實用的方法是在創建時告訴“生成器的生成器”是否生成生成器或列表。 雖然這不像讓list神奇地知道該做什么那樣方便,但它似乎比擁有一個特殊的to_list函數更舒服。

def gengen(n, listmode=False):
    for i in range(n):
        def gen():
            for k in range(i+1):
                yield k
        yield list(gen()) if listmode else gen()

根據listmode參數,這可以用於生成生成器或列表。

for gg in gengen(5, False):
    print gg, list(gg)
print list(gengen(5, True))

暫無
暫無

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

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