(Note that this applies to CPython, and may be different in other implementations)
Python code is parsed and compiled into bytecode. You can see the instructions used with the dis module.
>>> def f(x):
... x = [1, 2, 3, 4]
>>> dis.dis(f)
2 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (3)
6 LOAD_CONST 4 (4)
8 BUILD_LIST 4
10 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
>>> print(dis.Bytecode(f).info())
Name: f
Filename: <stdin>
Argument count: 1
Kw-only arguments: 0
Number of locals: 1
Stack size: 4
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
0: None
1: 1
2: 2
3: 3
4: 4
Variable names:
0: x
As you can see, integer literals are constants, but lists have to be built everytime.
This is a relatively fast operation (Probably even quicker than looking up a global, but the time is still negligible)
If you had a function g that used a tuple instead, it is loaded as a constant:
>>> def g(x):
... x = (1, 2, 3, 4)
>>> dis.dis(g)
2 0 LOAD_CONST 5 ((1, 2, 3, 4))
2 STORE_FAST 0 (x)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE
>>> print(dis.Bytecode(g).info())
Name: g
Filename: <stdin>
Argument count: 1
Kw-only arguments: 0
Number of locals: 1
Stack size: 4
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
0: None
1: 1
2: 2
3: 3
4: 4
5: (1, 2, 3, 4)
Variable names:
0: x
But this seems like a case of premature optimisation.
The constants stored for a function can be found as function.__code__.co_consts.
>>> g.__code__.co_consts
(None, 1, 2, 3, 4, (1, 2, 3, 4))
The reason a new list has to be built every time is so that if the list is changed, it won't affect a list that is loaded everytime.
And the tuple optimisation goes away if it isn't a list of constants.
>>> def h(x):
... x = (1, 2, 3, x)
>>> dis.dis(h)
2 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (3)
6 LOAD_FAST 0 (x)
8 BUILD_TUPLE 4
10 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
>>> print(dis.Bytecode(h).info())
Name: h
Filename: <stdin>
Argument count: 1
Kw-only arguments: 0
Number of locals: 1
Stack size: 4
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
0: None
1: 1
2: 2
3: 3
Variable names:
0: x
xas a constant in python? How would the compiler know thatxisn't going to change (in your#stuffsection for example)?