gpt4 book ai didi

生成器的 python 生成器?

转载 作者:太空狗 更新时间:2023-10-29 21:03:33 27 4
gpt4 key购买 nike

我写了一个读取 txt 文件的类。该文件由非空行 block 组成(我们称它们为“部分”),由空行分隔:

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]

由于生成的对象是生成器函数,而不仅仅是生成器,所以您需要这样做

[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 中展示的黑暗、 secret 的 hack 方法(我需要写它),但不要这样做!

正如所 promise 的那样,hack(针对 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,我没有骗你,改变__class__ 属性。

由于布局冲突,我们必须使用 UserList 类并隐藏其所有方法,这只是另一层 crud。

基本上,请不要使用此 hack。不过,您可以把它当作幽默来享受。

关于生成器的 python 生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19033401/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com