如何在 python 中保存迭代器的状态?
How to save state of an iterator in python?
我有一个非常大的迭代器。由于缺乏资源(网络、内存和时间),我无法一步执行我的程序。
所以我认为如果我 运行 我的程序直到迭代器中的第 10000 个元素然后保存它的状态会很好。下次我 运行 编程时,它从迭代器中的第 10001 个元素继续。
这是我使用的代码:
import itertools
import requests
POSSIBLE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
URL = "URL?key={code}"
all_possible = itertools.combinations_with_replacement(POSSIBLE_CHARS, 29)
counter = itertools.count(start=1)
for c in all_possible:
print("Try {}:".format(next(counter)), c)
c_url = URL.format(code=c)
resp = requests.get(c_url)
if resp.status_code == 200:
print("C found:", c)
with open(c+".gif", 'b') as f:
f.write(resp.content)
此 link 展示了如何在单次执行中继续迭代器。但我想要的是停止程序并再次执行。
So I thought it would be nice if I run my program till 10000th element in iterator and then save its state. next time I run program it continues from 10001st element in iterator.
您很幸运,因为 itertools.combinations_with_replacement
对象具有允许设置状态的 API。这被 Python 中的 copy
模块使用,但没有理由你不能也挂钩。
例如第 10,001 项 是这样的:
>>> all_possible = itertools.combinations_with_replacement(POSSIBLE_CHARS, 29)
>>> for i in range(10_000):
... next(all_possible)
...
>>> "".join(next(all_possible))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwI'
要 "fast-forward" 在新实例中添加到此项,它将是:
>>> new_iterator = itertools.combinations_with_replacement(POSSIBLE_CHARS, 29)
>>> state = (0,)*26 + (5, 22, 33)
>>> new_iterator.__setstate__(state)
>>> "".join(next(new_iterator))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwI'
>>> "".join(next(new_iterator))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwJ'
>>> new_iterator.__setstate__(state) # bonus: rewind iterator!
>>> "".join(next(new_iterator))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwI'
理解为什么组合 10,001 对应于一些长度为 29 的元组,例如 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 22, 33), 我邀请您浏览 CPython 来源 to see how combinations objects allow themselves to be statefully copied and also the relevant section of the pickle
docs.
如果您不需要针对错误或恶意构造的数据的安全性,那么您可能会考虑简单地将此类迭代器腌制到文件中,而不是手动挂接到 __setstate__
方法。
我有一个非常大的迭代器。由于缺乏资源(网络、内存和时间),我无法一步执行我的程序。
所以我认为如果我 运行 我的程序直到迭代器中的第 10000 个元素然后保存它的状态会很好。下次我 运行 编程时,它从迭代器中的第 10001 个元素继续。
这是我使用的代码:
import itertools
import requests
POSSIBLE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
URL = "URL?key={code}"
all_possible = itertools.combinations_with_replacement(POSSIBLE_CHARS, 29)
counter = itertools.count(start=1)
for c in all_possible:
print("Try {}:".format(next(counter)), c)
c_url = URL.format(code=c)
resp = requests.get(c_url)
if resp.status_code == 200:
print("C found:", c)
with open(c+".gif", 'b') as f:
f.write(resp.content)
此 link 展示了如何在单次执行中继续迭代器。但我想要的是停止程序并再次执行。
So I thought it would be nice if I run my program till 10000th element in iterator and then save its state. next time I run program it continues from 10001st element in iterator.
您很幸运,因为 itertools.combinations_with_replacement
对象具有允许设置状态的 API。这被 Python 中的 copy
模块使用,但没有理由你不能也挂钩。
例如第 10,001 项 是这样的:
>>> all_possible = itertools.combinations_with_replacement(POSSIBLE_CHARS, 29)
>>> for i in range(10_000):
... next(all_possible)
...
>>> "".join(next(all_possible))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwI'
要 "fast-forward" 在新实例中添加到此项,它将是:
>>> new_iterator = itertools.combinations_with_replacement(POSSIBLE_CHARS, 29)
>>> state = (0,)*26 + (5, 22, 33)
>>> new_iterator.__setstate__(state)
>>> "".join(next(new_iterator))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwI'
>>> "".join(next(new_iterator))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwJ'
>>> new_iterator.__setstate__(state) # bonus: rewind iterator!
>>> "".join(next(new_iterator))
'aaaaaaaaaaaaaaaaaaaaaaaaaafwI'
理解为什么组合 10,001 对应于一些长度为 29 的元组,例如 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 22, 33), 我邀请您浏览 CPython 来源 to see how combinations objects allow themselves to be statefully copied and also the relevant section of the pickle
docs.
如果您不需要针对错误或恶意构造的数据的安全性,那么您可能会考虑简单地将此类迭代器腌制到文件中,而不是手动挂接到 __setstate__
方法。