函数式编程最著名的功能是惰性求值和无限列表。在Python中,通常使用生成器来实现这些功能。但函数式编程的原则之一是不变性,而生成器也不是一成不变的。恰好相反。每次在生成器上调用 next()
时,它都会更改其内部状态。
一个可能的解决方法是在调用 next()
之前复制生成器。这适用于某些生成器,例如 count()
。 (也许 count()
不是生成器?)
from itertools import count
count_gen = count()
count_gen_copy = copy(count_gen)
print(next(count_gen), next(count_gen), next(count_gen)) # => 0 1 2
print(next(count_gen_copy), next(count_gen_copy), next(count_gen_copy)) # => 0 1 2
但是如果我定义自己的生成器,例如 my_count()
,我无法复制它。
def my_count(n=0):
while True:
yield n
n += 1
my_count_gen = my_count()
my_count_gen_copy = copy(my_count_gen)
print(next(my_count_gen), next(my_count_gen), next(my_count_gen))
print(next(my_count_gen_copy), next(my_count_gen_copy), next(my_count_gen_copy))
当我尝试执行copy(my_count_gen)
时收到错误消息:TypeError: can't pickle Generator objects
。
有没有办法解决这个问题,或者还有其他方法吗?
也许问这个问题的另一种方式是:当 copy()
复制 copy_gen
时,它在复制什么?
谢谢。
附注如果我使用 __iter__()
而不是 copy()
,则 __iter__()
版本的行为与原始版本类似。
my_count_gen = my_count()
my_count_gen_i = my_count_gen.__iter__()
print(next(my_count_gen), next(my_count_gen), next(my_count_gen)) # => 0 1 2
print(next(my_count_gen_i), next(my_count_gen_i), next(my_count_gen_i)) # => 3 4 5
最佳答案
无法在 Python 中复制任意生成器。手术根本没有意义。生成器可能依赖于各种其他不可复制的资源,例如文件句柄、数据库连接、锁、工作进程等。如果生成器持有锁并且您复制了它,那么锁会发生什么情况?如果生成器位于数据库事务中并且您复制它,事务会发生什么?
您认为可复制生成器的东西根本不是生成器。它们是其他迭代器类的实例。如果你想编写自己的迭代器类,你可以:
class MyCount:
def __init__(self, n=0):
self._n = n
def __iter__(self):
return self
def __next__(self):
retval = self._n
self._n += 1
return retval
您以这种方式编写的某些迭代器甚至可能是可以合理复制的。其他人,copy.copy
会做一些完全不合理且无用的事情。
关于python - 有没有办法在Python中复制任意生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63892520/