Hard coded variables in python function

Sometimes some values ​​/ strings are hardcoded in functions. For example, in the following function, I define a β€œconstant” comparison string and check it.

def foo(s): c_string = "hello" if s == c_string: return True return False 

Without discussing too much about why this is bad for this, and how it should be defined in the external field, I wonder what happens behind the scenes when defined in this way. <w> Does the line create every call?
If instead of the string "hello" it was a list: [1,2,3] (or a list with mutable content, if it matters), will this happen?

+5
source share
1 answer

Since the string is immutable (like a tuple), it is stored with the bytecode object for the function. It loads with a very simple and quick index search. This is actually faster than a global search.

You can see this when parsing bytecode using the dis.dis() function :

 >>> import dis >>> def foo(s): ... c_string = "hello" ... if s == c_string: ... return True ... return False ... >>> dis.dis(foo) 2 0 LOAD_CONST 1 ('hello') 3 STORE_FAST 1 (c_string) 3 6 LOAD_FAST 0 (s) 9 LOAD_FAST 1 (c_string) 12 COMPARE_OP 2 (==) 15 POP_JUMP_IF_FALSE 22 4 18 LOAD_GLOBAL 0 (True) 21 RETURN_VALUE 5 >> 22 LOAD_GLOBAL 1 (False) 25 RETURN_VALUE >>> foo.__code__.co_consts (None, 'hello') 

The operation code LOAD_CONST loads a string object from the co_costs array, which is part of the code object for the function; this link is pushed to the top of the stack. The STORE_FAST takes the link from the top of the stack and stores it in the locals array, again a very simple and fast operation.

For mutable literals ( {..} , [..] ), special operation codes construct an object, and the contents are still considered as constants as much as possible (more complex structures simply follow the same building blocks):

 >>> def bar(): return ['spam', 'eggs'] ... >>> dis.dis(bar) 1 0 LOAD_CONST 1 ('spam') 3 LOAD_CONST 2 ('eggs') 6 BUILD_LIST 2 9 RETURN_VALUE 

The BUILD_LIST call creates a new list object using two constant string objects.

Interesting fact: if you used a list object for a membership test ( something in ['option1', 'option2', 'option3'] Python knows that the list object will never be mutated and will convert it to a tuple for you at compile time (the so-called peephole optimization). The same applies to a set of literals that can be converted to a frozenset() object, but only in Python 3.2 and later. See the tuple or list when using the 'in' in the 'if' article?

Note that your sample function uses booleans rather verbosely; you could just use:

 def foo(s): c_string = "hello" return s == c_string 

for the same result, avoiding LOAD_GLOBAL calls in Python 2 (Python 3 made the keywords True and False , so the values ​​can also be stored as constants).

+11
source

All Articles