funny generator behaviour

Arnaud Delobelle arnodel at googlemail.com
Thu Dec 4 17:57:57 CET 2008


Edvin Fuglebakk <Edvin.Fuglebakk at ii.uib.no> writes:

> I have written a generator that puzzles me:
>
> The generator is supposed to create ordered selections of a set of
> objects. repetition of objects is allowed and the selections should be
> of a size determined by a pramter to the generator.
>
> Now, if I try to accummulate the generated selections into a list I
> get some peculiar behaviour that I hope maybe some of you can help me
> understand:
>
> Help much appreciated
> -Edvin
>
> #straightforward acumulation. Does not give the expected result
>>>> d=[]
>>>> for f in orderedCombinations([1,2],3):
> ...     d.append(f)
> ...
>>>> d
> [[1], [2], [1], [2], [1], [2], [1], [2]]
>
> #accumulating shallow copies of the genereated combinations works:
>>>> d=[]
>>>> for f in orderedCombinations([1,2],3):
> ...     d.append(f[:])
> ...
>>>> d
> [[1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2], [2, 1, 1], [2, 1, 2], [2,
> 2, 1], [2, 2, 2]]
>
>
> #The generator:
> def orderedCombinations(pool, k):
>    """
>    Generator yielding ordered selections of size k with repetition
> from pool.
>    """
>
>    if k == 1:
>        for m in pool:
>            yield [m]
>
>    if k > 1:
>
>        for m in pool:
>            for combo in orderedCombinations(pool, k-1):
>
>                #insert and pop to avoid copying entire list
>                combo.insert(0,m)
>                yield combo

I haven't tried your code but I think the problem is that you yield a
list above and then mutate it below, so when you generate the next
combination the previous one is mutated.  Change the above line to

                yield list(combo)

and it should sort the problem. 

>                combo.pop(0)

-- 
Arnaud



More information about the Python-list mailing list