简体   繁体   中英

What is the difference between these two (Python) code samples?

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...

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.

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.

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