这两个(Python)代码示例之间有什么区别?

时间:2014-01-13 17:29:49

标签: python

我是一名蟒蛇初学者。我想知道......

Q1:sample2是否比sample1更快,内存使用量更少?(因为它没有声明并分配变量)

Q2:哪个样本更适合“大型”计划?(即使对于大型计划来说,差异是否重要?)

样本1:

session = request.session
session['v1'] = 1
session['v2'] = 2
session['v2'] = 3
if session['v1'] == 1:
    session['v4'] = 4

样品2:

request.session['v1'] = 1
request.session['v2'] = 2
request.session['v2'] = 3
if request.session['v1'] == 1:
    request.session['v4'] = 4

不是为了过早优化。只是为了知道...

2 个答案:

答案 0 :(得分:5)

第一个代码是更快,因为它避免了request及其属性的所有查找。查看字节码的差异:

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   

对战:

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  

请注意第二个字节码中的所有额外LOAD_GLOBALLOAD_ATTR,并请注意LOAD_FAST LOAD_GLOBAL快,因为LOAD_FAST执行简单的数组查找,而LOAD_GLOBAL必须查找全局字典(需要计算变量的哈希等)。

第一个版本只有一个LOAD_GLOBAL和一个LOAD_ATTR

事实上,如果我们测试他们的速度:

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

第一个几乎快两倍。 但请注意,它们都很快,可能它们的速度无关紧要。 如果request是局部变量,速度差会减少一点。

第二个还有另一个缺点:它反复重复同样的事情。使代码更大,可读性更低,并引入更高的拼写错误。 我认为,这是那些与这些片段无关的唯一的事物。 如果您出于性能原因选择它们:那绝对是过早的优化。

答案 1 :(得分:2)

它可能没有多大区别。第一种解决方案可能无限快。

除了你的解决方案(两者都很好),并假设request.session类似dict,你可能会考虑:

request.session.update({
  'v1': 1,
  'v2': 2,
  …
})

取决于更改的数量以及新信息是否已存在于词典中。