Python Local Variable Initialization
Solution 1:
You can look at what the interpreter does using the dis
module:
defdo_sth():
d = {'a':2, 'b':3}
print(id(d))
import dis
dis.dis(do_sth)
will print
20 BUILD_MAP 23 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)
320 LOAD_GLOBAL 0 (id)
23 LOAD_FAST 0 (d)
26 CALL_FUNCTION 129 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.
Solution 2:
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:
defprint_3():
print(3)
defdo_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.
Solution 3:
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 = []
defdo_sth():
local_dict = { 'a': 1, 'b': 2, 'c': 3, ... }
...
defdo_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, ... }
Solution 4:
it would be easy to check with the is
operator:
deftest():
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
Solution 5:
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:
defdo_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.
Post a Comment for "Python Local Variable Initialization"