python - 使用 itertools.product 并希望播种一个值

标签 python image download seed python-itertools

所以我写了一个小脚本来从网站下载图片。它通过一个 7 字母字符值,其中第一个字符始终是一个数字。问题是如果我想停止脚本并重新启动它,我必须重新开始。

我能否以某种方式将我获得的最后一个值作为 itertools.product 的种子,这样我就不必再次遍历它们。

感谢任何输入。

部分代码如下:

numbers = '0123456789'
alnum = numbers + 'abcdefghijklmnopqrstuvwxyz'

len7 = itertools.product(numbers, alnum, alnum, alnum, alnum, alnum, alnum) # length 7

for p in itertools.chain(len7):
    currentid = ''.join(p) 

    #semi static vars
    url = 'http://mysite.com/images/'
    url += currentid

    #Need to get the real url cause the redirect
    print "Trying " + url
    req = urllib2.Request(url)
    res = openaurl(req)
    if res == "continue": continue
    finalurl = res.geturl()

    #ok we have the full url now time to if it is real
    try: file = urllib2.urlopen(finalurl)
    except urllib2.HTTPError, e:
        print e.code

    im = cStringIO.StringIO(file.read())
    img = Image.open(im)
    writeimage(img)

最佳答案

这里有一个基于pypy库代码的解决方案(感谢agf在评论中的建议)。

状态可通过 .state 属性获得,并可通过 .goto(state) 重置,其中 state 是序列(从 0 开始)。最后有一个演示(恐怕你需要向下滚动)。

这比丢弃值要快得多。

> cat prod.py 

class product(object):

    def __init__(self, *args, **kw):
        if len(kw) > 1:
            raise TypeError("product() takes at most 1 argument (%d given)" %
                             len(kw))
        self.repeat = kw.get('repeat', 1)
        self.gears = [x for x in args] * self.repeat
        self.num_gears = len(self.gears)
        self.reset()

    def reset(self):
        # initialization of indicies to loop over
        self.indicies = [(0, len(self.gears[x]))
                         for x in range(0, self.num_gears)]
        self.cont = True
        self.state = 0

    def goto(self, n):
        self.reset()
        self.state = n
        x = self.num_gears
        while n > 0 and x > 0:
            x -= 1
            n, m = divmod(n, len(self.gears[x]))
            self.indicies[x] = (m, self.indicies[x][1])
        if n > 0:
            self.reset()
            raise ValueError("state exceeded")

    def roll_gears(self):
        # Starting from the end of the gear indicies work to the front
        # incrementing the gear until the limit is reached. When the limit
        # is reached carry operation to the next gear
        self.state += 1
        should_carry = True
        for n in range(0, self.num_gears):
            nth_gear = self.num_gears - n - 1
            if should_carry:
                count, lim = self.indicies[nth_gear]
                count += 1
                if count == lim and nth_gear == 0:
                    self.cont = False
                if count == lim:
                    should_carry = True
                    count = 0
                else:
                    should_carry = False
                self.indicies[nth_gear] = (count, lim)
            else:
                break

    def __iter__(self):
        return self

    def next(self):
        if not self.cont:
            raise StopIteration
        l = []
        for x in range(0, self.num_gears):
            index, limit = self.indicies[x]
            l.append(self.gears[x][index])
        self.roll_gears()
        return tuple(l)

p = product('abc', '12')
print list(p)
p.reset()
print list(p)
p.goto(2)
print list(p)
p.goto(4)
print list(p)
> python prod.py 
[('a', '1'), ('a', '2'), ('b', '1'), ('b', '2'), ('c', '1'), ('c', '2')]
[('a', '1'), ('a', '2'), ('b', '1'), ('b', '2'), ('c', '1'), ('c', '2')]
[('b', '1'), ('b', '2'), ('c', '1'), ('c', '2')]
[('c', '1'), ('c', '2')]

你应该多测试一下 - 我可能犯了一个愚蠢的错误 - 但这个想法很简单,所以你应该能够修复它 :o) 你可以自由使用我的更改;不知道原始的 pypy 许可证是什么。

还有 state 并不是真正的完整状态——它不包括原始参数——它只是序列的索引。也许称它为索引会更好,但是代码中已经有索引了……

更新

这是一个更简单的版本,它的想法相同,但通过转换数字序列来工作。所以你只需 imap 它超过 count(n) 就可以得到 n 的序列偏移量。

> cat prod2.py 

from itertools import count, imap

def make_product(*values):
    def fold((n, l), v):
        (n, m) = divmod(n, len(v))
        return (n, l + [v[m]])
    def product(n):
        (n, l) = reduce(fold, values, (n, []))
        if n > 0: raise StopIteration
        return tuple(l)
    return product

print list(imap(make_product(['a','b','c'], [1,2,3]), count()))
print list(imap(make_product(['a','b','c'], [1,2,3]), count(3)))

def product_from(n, *values):
    return imap(make_product(*values), count(n))

print list(product_from(4, ['a','b','c'], [1,2,3]))

> python prod2.py 
[('a', 1), ('b', 1), ('c', 1), ('a', 2), ('b', 2), ('c', 2), ('a', 3), ('b', 3), ('c', 3)]
[('a', 2), ('b', 2), ('c', 2), ('a', 3), ('b', 3), ('c', 3)]
[('b', 2), ('c', 2), ('a', 3), ('b', 3), ('c', 3)]

(这里的缺点是,如果你想停止并重新启动,你需要自己跟踪你已经使用了多少)

关于python - 使用 itertools.product 并希望播种一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9864809/

相关文章:

python - 如何在python中下载登录表单后面网页的大媒体链接?

php - 如果我下载它,mysql会给出不同的结果

r - 无法从 Shiny 下载 .png 文件

python - Anaconda 提示立即关闭——系统无法找到指定的注册表项或值

python - 自动刷新伴侣面板小程序

image - 调整图像中的 ROI 大小

html - CSS-无法并排放置图像列表

java - 程序应该显示整个图像只显示它的一部分

java - 使用 java : How to authenticate? 从 Internet 下载文件

Python POST 请求,无需重新加载页面