简体   繁体   中英

Python local variable initialization

I'm rather new to python and I'm wondering how local variables work. Let's start with an example of a simple method:

def do_sth():
    local_dict = { 'a': 1, 'b': 2, 'c': 3, ... }
    ...

Let's assume that local_dict is used like a sort of const variable. And here's the question: it is created every time when do_sth() is invoked or it is created once and is kept somewhere in do_sth() internals?

You can look at what the interpreter does using the dis module:

def do_sth():
    d = {'a':2, 'b':3}
    print(id(d))


import dis
dis.dis(do_sth)

will print

  2           0 BUILD_MAP                2
              3 LOAD_CONST               1 (2)
              6 LOAD_CONST               2 ('a')
              9 STORE_MAP           
             10 LOAD_CONST               3 (3)
             13 LOAD_CONST               4 ('b')
             16 STORE_MAP           
             17 STORE_FAST               0 (d)

  3          20 LOAD_GLOBAL              0 (id)
             23 LOAD_FAST                0 (d)
             26 CALL_FUNCTION            1
             29 PRINT_ITEM          
             30 PRINT_NEWLINE       
             31 LOAD_CONST               0 (None)
             34 RETURN_VALUE        

which shows that the interpreter is rebuilding the value every time the function is called.

Every time do_sth() is invoked. This is important because it allows you to make modifications to local_dict inside the function and it won't have any effect on other calls. The interpreter is not smart enough to see if you won't change it, especially because Python is so dynamic that there are some very roundabout ways you can cause it to change.

Here's how you can prove to yourself that the dictionary keeps getting recreated:

def print_3():
    print(3)

def do_sth():
    local_dict = {'a': print_3()}

do_sth()
do_sth()
do_sth()

This prints 3 ... 3 times.

I think global variables are fine for optimising this, but if you really want, how about this:

def do_sth():
    return do_sth.local_dict

do_sth.local_dict = {'a': print_3()}

Technically this can still be accessed by everyone but it's clearer what it belongs to.

Local variable are always created in the scope of a function. There are collected by the garbage collector once the program counter quits function (scope of the local variable).

global_dict = []

def do_sth():
    local_dict = { 'a': 1, 'b': 2, 'c': 3, ... }
    ...

def do_other_task():
   #local_dict not visible. It's outside of scope. 
   global global_dict # fetch memory address of previously declared global_dict
   global_dict = { 'a': 1, 'b': 2, 'c': 3, ... }

it would be easy to check with the is operator:

def test():
    return {'a': 1, 'b': 2, 'c': 3}

>>> test() is test() #did both produce the same object in memory space?
False

This makes a lot of sense for mutable objects or the mutable default argument trap would come up everywhere.

However there are values that are stored as constants and those can be seen using dis as constants are loaded with the LOAD_CONST byte code:

>>> dis.dis(lambda:1)
  1           0 LOAD_CONST               1 (1)
              3 RETURN_VALUE
>>> dis.dis(lambda:(1,True, 10*1000, "a"))
  1           0 LOAD_CONST               7 ((1, True, 10000, 'a'))
              3 RETURN_VALUE
>>> dis.dis(lambda:[1,2,3]) #list is mutable
  1           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              9 BUILD_LIST               3
             12 RETURN_VALUE
>>> dis.dis(lambda:{"a":1}) #dict is also mutable
  1           0 LOAD_CONST               1 ('a')
              3 LOAD_CONST               2 (1)
              6 BUILD_MAP                1
              9 RETURN_VALUE

The other answers are correct, I would just add this.

I would rather do, in such case, either:

constant_dict = { 'a': 1, 'b': 2, 'c': 3, ... }
def do_sth():
    # do something reading constant_dict

do_sth()

or but less preferable :

def do_sth(local_dict = { 'a': 1, 'b': 2, 'c': 3, ... }):
    # do something reading local_dict

do_sth()

In both cases, python would not have to reallocate the memory for the variable, because it got declared and allocated when the interpreter reads the python file.

Correct me if I'm wrong.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM