【问题标题】:How to save state of an iterator in python?如何在python中保存迭代器的状态?
【发布时间】:2019-07-05 08:44:40
【问题描述】:

我有一个非常大的迭代器。由于缺乏资源(网络、内存和时间),我无法一步执行我的程序。

所以我认为如果我将程序运行到迭代器中的第 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 展示了如何在单次执行中继续迭代器。但我想要的是停止程序并再次执行。

【问题讨论】:

    标签: python iterator itertools python-3.7


    【解决方案1】:

    所以我认为如果我将程序运行到迭代器中的第 10000 个元素然后保存它的状态会很好。下次我运行程序时,它会从迭代器中的第 10001 个元素继续。

    你很幸运,因为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'
    

    要在新实例中“快进”到该项目,它会是:

    >>> 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 以及pickle docs 的相关部分。

    如果您不需要针对错误或恶意构造的数据提供安全性,那么您可以考虑简单地将此类迭代器腌制到文件中,而不是手动挂钩到 __setstate__ 方法。

    【讨论】:

    • 谢谢。我认为它的 10000 不是 10_000 循环。
    • @Javadmk 这是 Python 3.6 中的一个新特性,可以让较大的 int 文字更易于阅读;见python.org/dev/peps/pep-0515
    猜你喜欢
    • 2018-12-30
    • 2022-01-15
    • 2014-05-08
    • 1970-01-01
    • 2021-06-27
    • 2022-06-22
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    相关资源
    最近更新 更多