Skip to content Skip to sidebar Skip to footer

"tuple Comprehensions" And The Star Splat/unpack Operator *

I just read the question Why is there no tuple comprehension in Python? In the comments of the accepted answer, it is stated that there are no true 'tuple comprehensions'. Instead

Solution 1:

To me, it seems like the second example is also one where a generator object is created first. Is this correct?

Yes, you're correct, checkout the CPython bytecode:

>>> import dis
>>> dis.dis("*(thing for thing in thing),")
  10 LOAD_CONST               0 (<code object <genexpr> at 0x7f56e9347ed0, file "<dis>", line 1>)
              2 LOAD_CONST               1 ('<genexpr>')
              4 MAKE_FUNCTION            06 LOAD_NAME                0 (thing)
              8 GET_ITER
             10 CALL_FUNCTION            112 BUILD_TUPLE_UNPACK       114 POP_TOP
             16 LOAD_CONST               2 (None)
             18 RETURN_VALUE

Is there any difference between these expressions in terms of what goes on behind the scenes? In terms of performance? I assume the first and third could have latency issues while the second could have memory issues (as is discussed in the linked comments).

My timings suggest the first 1 is slightly faster, presumably because the unpacking is more expensive via BUILD_TUPLE_UNPACK than the tuple() call:

>>>from timeit import timeit>>>deff1(): tuple(thing for thing inrange(100000))...>>>deff2(): *(thing for thing inrange(100000)),...>>>timeit(lambda: f1(), number=100)
0.5535585517063737
>>>timeit(lambda: f2(), number=100)
0.6043887557461858

Comparing the first one and the last, which one is more pythonic?

The first one seems far more readable to me, and also will work across different Python versions.

Post a Comment for ""tuple Comprehensions" And The Star Splat/unpack Operator *"