Is a persistent list used in a loop built / deleted with each pass?

Will the following snippet create and destroy a list of constants in each cycle, entailing any (albeit small) overhead, or is it a list created once?

for i in <some-type-of-iterable>: if i in [1,3,5,18,3457,40567]: print(i) 

I ask about the Python β€œstandard”, such as the existing one, and about the general implementation of CPython.
I know that this example is contrived, and also that worrying about performance using CPython is stupid, but I'm just curious.

+7
python
source share
2 answers

Another example with Python 3.5, a list is created for each iteration.

 >>> import dis >>> def func(): ... for i in iterable: ... for j in [1,2,3]: ... print(i+j) ... >>> dis.dis(func) 2 0 SETUP_LOOP 54 (to 57) 3 LOAD_GLOBAL 0 (iterable) 6 GET_ITER >> 7 FOR_ITER 46 (to 56) 10 STORE_FAST 0 (i) 3 13 SETUP_LOOP 37 (to 53) 16 LOAD_CONST 1 (1) # building list 19 LOAD_CONST 2 (2) 22 LOAD_CONST 3 (3) 25 BUILD_LIST 3 28 GET_ITER >> 29 FOR_ITER 20 (to 52) # inner loop body begin 32 STORE_FAST 1 (j) 4 35 LOAD_GLOBAL 1 (print) 38 LOAD_FAST 0 (i) 41 LOAD_FAST 1 (j) 44 BINARY_ADD 45 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 48 POP_TOP 49 JUMP_ABSOLUTE 29 # inner loop body end >> 52 POP_BLOCK >> 53 JUMP_ABSOLUTE 7 # outer loop end, # jumping back before list creation >> 56 POP_BLOCK >> 57 LOAD_CONST 0 (None) 60 RETURN_VALUE 
+2
source share

It depends on the implementation and version of python and how persistent lists are used. On Cpython2.7.10 with your example, it seems like the answer is that the list in the state of the if is created only once ...

 >>> def foo(): ... for i in iterable: ... if i in [1, 3, 5]: ... print(i) ... >>> import dis >>> dis.dis(foo) 2 0 SETUP_LOOP 34 (to 37) 3 LOAD_GLOBAL 0 (iterable) 6 GET_ITER >> 7 FOR_ITER 26 (to 36) 10 STORE_FAST 0 (i) 3 13 LOAD_FAST 0 (i) 16 LOAD_CONST 4 ((1, 3, 5)) 19 COMPARE_OP 6 (in) 22 POP_JUMP_IF_FALSE 7 4 25 LOAD_FAST 0 (i) 28 PRINT_ITEM 29 PRINT_NEWLINE 30 JUMP_ABSOLUTE 7 33 JUMP_ABSOLUTE 7 >> 36 POP_BLOCK >> 37 LOAD_CONST 0 (None) 40 RETURN_VALUE 

Note: 16 LOAD_CONST 4 ((1, 3, 5))

The Peeon peephole optimizer turned our list into a tuple (thanks python!) And saved it as a constant. Please note that the spy optimizer can only perform these transformations on objects if it knows that you, since the programmer has absolutely no way to get a link to a list (otherwise you can change the list and change the meaning of the code). As far as I know, they do this optimization only for list , set literals, which consist of completely constants and are the RHS of the in operator. There may be other cases that I do not know about ( dis.dis is your friend for finding these optimizations).

I hinted at it above, but you can do the same with set-literals in later versions of python (in python3.2 +, set converted to frozenset constant). The advantage is that set / frozenset have faster average membership testing than list / tuple .

+3
source share

All Articles