Usando itertools.product y querer sembrar un valor

Así que escribí un pequeño script para descargar imágenes de un sitio web. Pasa a través de un valor de carácter alfa 7, donde el primer carácter es siempre un número. El problema es que si quiero detener el script y volver a iniciarlo, tengo que empezar de nuevo.

¿Puedo sembrar itertools.product de alguna manera con el último valor que obtuve para no tener que pasar por todos ellos nuevamente

Gracias por cualquier entrada.

Aquí es parte del código:

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) 

Aquí hay una solución basada en el código de la biblioteca de pypy (gracias a la sugerencia de agf en los comentarios).

el estado está disponible a través del atributo .state y se puede restablecer a través de .goto(state) donde state es un índice en la secuencia (comenzando en 0). Hay una demostración al final (tienes que desplazarte hacia abajo, me temo).

Esto es mucho más rápido que descartar valores.

 > 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')] 

deberías probarlo más, es posible que haya cometido un error tonto, pero la idea es bastante simple, por lo que deberías poder solucionarlo: o) eres libre de usar mis cambios; ni idea de lo que es la licencia pypy original.

Además, el state no es realmente el estado completo, no incluye los argumentos originales, solo es un índice en la secuencia. tal vez hubiera sido mejor llamarlo índice, pero ya hay indicios [sic] en el código …

actualizar

Aquí hay una versión más simple que es la misma idea pero funciona al transformar una secuencia de números. así que simplemente lo imap el count(n) para obtener la secuencia compensada por 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)] 

(el inconveniente aquí es que si desea detenerse y reiniciarse, debe haberse mantenido al tanto de cuántos ha usado)

Una vez que haya recorrido el iterador de manera justa, tomará un tiempo llegar al lugar usando Droptime.

Probablemente deberías adaptar una receta como esta para que puedas guardar el estado con un pickle entre ejecuciones.

Asegúrese de que su script solo pueda ejecutarse una vez a la vez, o necesitará algo más detallado, como un proceso de servidor que distribuya los identificadores a los scripts.

Si sus secuencias de entrada no tienen ningún valor duplicado, esto puede ser más rápido que el dropwhile para avanzar el product ya que no requiere que compare todos los valores eliminados al calcular el punto correcto para reanudar la iteración.

 from itertools import product, islice from operator import mul def resume_product(state, *sequences): start = 0 seqlens = map(len, sequences) if any(len(set(seq)) != seqlen for seq, seqlen in zip(sequences, seqlens)): raise ValueError("One of your sequences contains duplicate values") current = end = reduce(mul, seqlens) for i, seq, seqlen in zip(state, sequences, seqlens): current /= seqlen start += seq.index(i) * current return islice(product(*sequences), start + 1, end) seqs = '01', '23', '45', '678' # if I want to resume after '1247': for i in resume_product('1247', *seqs): # blah blah pass