Reputation: 84
I am a python beginner. I am wondering...
Q1: Is sample2 is bit faster and bit less memory usage than sample1? (because it does not declare and assigning a variable)
Q2: Which sample is better for 'big' programme? (is it matter the difference even for a big programme?)
Sample1:
session = request.session
session['v1'] = 1
session['v2'] = 2
session['v2'] = 3
if session['v1'] == 1:
session['v4'] = 4
Sample2:
request.session['v1'] = 1
request.session['v2'] = 2
request.session['v2'] = 3
if request.session['v1'] == 1:
request.session['v4'] = 4
Not for a premature optimization. Just for knowing...
Upvotes: 1
Views: 812
Reputation: 102029
The first code is faster because it avoids all the lookups of request
and its attribute. See the difference in bytecodes:
In [6]: dis.dis(test_first)
2 0 LOAD_GLOBAL 0 (request)
3 LOAD_ATTR 1 (session)
6 STORE_FAST 0 (session)
3 9 LOAD_CONST 1 (1)
12 LOAD_FAST 0 (session)
15 LOAD_CONST 2 ('v1')
18 STORE_SUBSCR
4 19 LOAD_CONST 3 (2)
22 LOAD_FAST 0 (session)
25 LOAD_CONST 4 ('v2')
28 STORE_SUBSCR
5 29 LOAD_CONST 5 (3)
32 LOAD_FAST 0 (session)
35 LOAD_CONST 4 ('v2')
38 STORE_SUBSCR
6 39 LOAD_FAST 0 (session)
42 LOAD_CONST 2 ('v1')
45 BINARY_SUBSCR
46 LOAD_CONST 1 (1)
49 COMPARE_OP 2 (==)
52 POP_JUMP_IF_FALSE 68
7 55 LOAD_CONST 6 (4)
58 LOAD_FAST 0 (session)
61 LOAD_CONST 7 ('v4')
64 STORE_SUBSCR
65 JUMP_FORWARD 0 (to 68)
>> 68 LOAD_CONST 0 (None)
71 RETURN_VALUE
Versus:
In [7]: dis.dis(test_second)
2 0 LOAD_CONST 1 (1)
3 LOAD_GLOBAL 0 (request)
6 LOAD_ATTR 1 (session)
9 LOAD_CONST 2 ('v1')
12 STORE_SUBSCR
3 13 LOAD_CONST 3 (2)
16 LOAD_GLOBAL 0 (request)
19 LOAD_ATTR 1 (session)
22 LOAD_CONST 4 ('v2')
25 STORE_SUBSCR
4 26 LOAD_CONST 5 (3)
29 LOAD_GLOBAL 0 (request)
32 LOAD_ATTR 1 (session)
35 LOAD_CONST 4 ('v2')
38 STORE_SUBSCR
5 39 LOAD_GLOBAL 0 (request)
42 LOAD_ATTR 1 (session)
45 LOAD_CONST 2 ('v1')
48 BINARY_SUBSCR
49 LOAD_CONST 1 (1)
52 COMPARE_OP 2 (==)
55 POP_JUMP_IF_FALSE 74
6 58 LOAD_CONST 6 (4)
61 LOAD_GLOBAL 0 (request)
64 LOAD_ATTR 1 (session)
67 LOAD_CONST 7 ('v4')
70 STORE_SUBSCR
71 JUMP_FORWARD 0 (to 74)
>> 74 LOAD_CONST 0 (None)
77 RETURN_VALUE
Notice all the extra LOAD_GLOBAL
and LOAD_ATTR
in the second bytecode and keep in mind that LOAD_FAST
is much faster than LOAD_GLOBAL
, because LOAD_FAST
does a simple array lookup, while LOAD_GLOBAL
has to lookup the global dictionary (which requires computing the hash of the variable etc.).
The first versions has a single LOAD_GLOBAL
and a single LOAD_ATTR
.
And indeed if we test their speeds:
In [8]: %timeit test_first()
1000000 loops, best of 3: 343 ns per loop
In [9]: %timeit test_second()
1000000 loops, best of 3: 542 ns per loop
The first one is almost twice as fast.
Note however that their are both fast, and probably their speed shouldn't matter.
The speed difference reduces a bit if request
is a local variable.
The second one has an other disadvantage: it repeats the same things a lot of times. Making the code both bigger, less readable and introducing higher chance of typos. This is, I believe, the only thing that matters of those snippets. If you were choosing them for performance reasons: that's absolutely premature optimization.
Upvotes: 7
Reputation: 77167
It probably doesn't make much of a difference. The first solution may be infinitesimally faster.
In addition to your solutions (both fine), and assuming request.session is dict-like, you might consider:
request.session.update({
'v1': 1,
'v2': 2,
…
})
depending on the number of changes and whether or not the new information is already in a dict.
Upvotes: 2