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.