[Python] Un generatore che non capisco

Pietro Battiston me a pietrobattiston.it
Ven 8 Nov 2013 12:41:20 CET


Salve a tutti,

ho scritto un generatore con poche righe di codice. Credo che il
contenuto sia inessenziale per la mia domanda, comunque lo trovate in
coda a questa email. Il punto è il seguente:

In [2]: g = enum_balanced(2)

In [3]: list(g)
Out[3]: [{0: [1], 1: []}, {0: [1], 1: []}]

Ora, questo risultato non era quello che mi aspettavo. Armato di
pazienza, mi sono messo a fare un po' di debugging, e...

In [4]: g = enum_balanced(2)

In [5]: list(g.next() for i in range(2))
Out[5]: [{0: [1], 1: [0]}, {0: [1], 1: [0]}]

... mi trovo completamente spiazzato.

C'è ovviamente qualcosa di basilare che mi sfugge riguardi agli
iterables e/o dict, dato che io mi aspetterei che i due comandi sopra
restituissero lo stesso output _qualsiasi cosa_ ci sia scritta nel corpo
g (purché "yieldi" due volte, ovviamente, e non sfrutti variabili
globali...)

Grazie mille di qualsiasi dritta
(N.B: anche eventuali consigli su come migliorare l'algoritmo in sé -
che sostanzialmente genera tutti le sequenze di N numeri
- che finiscono con il numero iniziale
- che non ripetono mai una sottosequenza di lunghezza 2
- e che, possibilmente, non siano isomorfe tra di loro,
... saranno benvenutissimi)


grazie,

Pietro


def enum_balanced(N, prefix=[], links=None):
    """
    Restituisci tutti i network balanced di N nodi.
    """
    
    if not links:
        links = {i : [] for i in range(N)}
    
    tutti = set(range(N))
    
    # Idea base: c'è un mapping biunivoco tra i balanced strongly
connected e i
    # cicli in una cricca che non ripassano mai dallo stesso link.
    
    # Per evitare (parte dei) grafi isomorfi, si può assumere che fino a
che si
    # chiude il primo ciclo, i nodi vengono visitati in ordine...
    if not prefix:
        prefix = [0]
        for i in range(1,N):
            prefix.append(1)
            links[i-1].append(i)
            gen = enum_balanced(N, prefix, links)
            while True:
                try:
                    n = gen.next()
                    yield n
                except StopIteration:
                    break
    
    if prefix[-1] == 0 and set(prefix) == tutti:
        gr = dict(links)
        yield gr
    
    for i in range(N):
        # ... ma forse questa altra assunzione non si può fare!
(verificare)
        if i != prefix[-1] and (not links[prefix[-1]] or i >
max(links[prefix[-1]])):
            links[prefix[-1]].append(i)
            gen = enum_balanced(N, prefix+[i], links)
            while True:
                try:
                    n = gen.next()
                    yield n
                except StopIteration:
                    break
            links[prefix[-1]].remove(i)



Maggiori informazioni sulla lista Python