Generator Comprehension different output from list comprehension?

后端 未结 4 1287
一向
一向 2020-12-05 09:55

I get different output when using a list comprehension versus a generator comprehension. Is this expected behavior or a bug?

Consider the following setup:

         


        
4条回答
  •  时光说笑
    2020-12-05 10:34

    This is happening because zip(*) call resulted in evaluation of the outer generator and this outer returned two more generators.

    (c[k], print(c)) for k in unique_keys)
    

    The evaluation of outer generator moved c to the second dict: {'a': 2, 'b':2}.

    Now when we are evaluating these generators individually they look for c somewhere, and as its value is now {'a': 2, 'b':2} you get the output as [(2, 2), (2, 2)].

    Demo:

    >>> def my_zip(*args):
    ...     print(args)
    ...     for arg in args:
    ...         print (list(arg))
    ...
    ... my_zip(*((c[k] for k in unique_keys) for c in all_configs))
    ...
    

    Output:

    # We have two generators now, means it has looped through `all_configs`.
    (. at 0x104415c50>, . at 0x10416b1a8>)
    [2, 2]
    [2, 2]
    

    The list-comprehension on the other hand evaluates right away and can fetch the value of current value of c not its last value.


    How to force it use the correct value of c?

    Use a inner function and generator function. The inner function can help us remember c's value using default argument.

    >>> def solve():
    ...     for c in all_configs:
    ...         def func(c=c):
    ...             return (c[k] for k in unique_keys)
    ...         yield func()
    ...
    
    >>>
    
    >>> list(zip(*solve()))
    [(1, 2), (3, 2)]
    

提交回复
热议问题