回的四种写法:记沈崴的dict法术

Zoom.Quiet <zoom.quiet@gmail.com>
sender-time     Sent at 11:41 (GMT+08:00). Current time there: 11:42 AM. ✆
to      python-cn@googlegroups.com
cc      pythontw@googlegroups.com,
guangzhou-tech-party <guangzhou-tech-party@googlegroups.com>
date    Mon, May 31, 2010 at 11:41
subject Re: [CPyUG] Re: 关于回的四种写法——python的get

2010/5/31 机械唯物主义 : linjunhalida <linjunhalida@gmail.com> > > 写的累死了,不知道发出来有没有意义?

绝对有,至少:
- 自个儿重温,并测试明确了大虾的经验
- 给社区留下了活动的文字记要
- 给大虾一个明确的反馈,知道是否讲到位了
- 给有心人一个异步学习的机会

意义大大的哈.,..

原义

昨天聚会,沈大侠分享了一下python dict get的四种方法:

Toggle line numbers
   1 # method 1
   2 # 采用异常捕捉来处理KeyError
   3 
   4 # 查询1次
   5 try:
   6     v = data[k]
   7 
   8 except KeyError:
   9     v = 12
  10  
  11 # method 2
  12 
  13 # 取值前先进行条件判断
  14 # 查询2次
  15 if data.has_key(k):
  16 
  17     v = data[k]
  18 else:
  19     v = 12
  20 
  21  
  22 # method 3
  23 # 和method2类似,只是利用in取代函数调用
  24 # 查询2次
  25 
  26 if k in data:
  27     v = data[k]
  28 
  29 else:
  30     v = 12
  31  
  32 # method 4
  33 # 函数调用
  34 
  35 # 查询1次
  36 v = data.get(k)
  37 if v == None:
  38     v = 12
提到几点
  • 函数调用是比较慢的,不如data[key]和key in data快。
    • 所以method2完全可以被method3替代。
    • method4在多数情况下也没有method2好。
  • 异常处理因为需要建立Error的对象,是最慢的。
    • 所以method1不很适用命中率低的状况。
  • method1和method4都只查询一次,
  • method2和method3都要查询两次,
  • 在某些查询是性能瓶颈的时候,不如method1和2快。

测试

为了对上面的估计作实际验证,我写了测试程序,如下:

Toggle line numbers
   1 #!/usr/bin/env python
   2 #-*- coding:utf-8 -*-
   3 """
   4 测试4种dict的get方法
   5 
   6 # method 1
   7 # 采用异常捕捉来处理KeyError
   8 # 查询1次
   9 try:
  10     v = data[k]
  11 except KeyError:
  12     v = 12
  13 
  14 # method 2
  15 # 取值前先进行条件判断
  16 # 查询2次
  17 if data.has_key(k):
  18     v = data[k]
  19 else:
  20     v = 12
  21 
  22 # method 3
  23 # 和method2类似,只是利用in取代函数调用
  24 # 查询2次
  25 if k in data:
  26     v = data[k]
  27 else:
  28     v = 12
  29 
  30 # method 4
  31 # 函数调用
  32 # 查询1次
  33 v = data.get(k)
  34 if v == None:
  35     v = 12
  36 
  37 """
  38 import time, json
  39 
  40 def test(data, k, count):
  41     times = []
  42     start = time.time()
  43     for i in range(count):
  44         #method 1
  45         try:
  46             v = data[k]
  47         except KeyError:
  48             v = 12
  49     end = time.time()
  50     print "method 1 spend time: %f s." % (end - start)
  51     times.append(end - start)
  52 
  53     start = time.time()
  54     for i in range(count):
  55         #method 2
  56         if data.has_key(k):
  57             v = data[k]
  58         else:
  59             v = 12
  60     end = time.time()
  61     print "method 2 spend time: %f s." % (end - start)
  62     times.append(end - start)
  63 
  64     start = time.time()
  65     for i in range(count):
  66         #method 3
  67         if k in data:
  68             v = data[k]
  69         else:
  70             v = 12
  71     end = time.time()
  72     print "method 3 spend time: %f s." % (end - start)
  73     times.append(end - start)
  74 
  75     start = time.time()
  76     for i in range(count):
  77         #method 4
  78         v = data.get(k)
  79         if v == None:
  80             v = 12
  81     end = time.time()
  82     print "method 4 spend time: %f s." % (end - start)
  83     times.append(end - start)
  84 
  85     return times
  86 
  87 def main():
  88     print "test hit"
  89     data = {'a': 12}
  90     k = 'a'
  91     times1 = test(data, k, 1000000)
  92     print 
  93 
  94     print "test not hit"
  95     data = {'a': 12}
  96     k = 'ab'
  97     times2 = test(data, k, 1000000)
  98     print
  99 
 100     print "test data IO"
 101     data = {'a': 12}
 102     k = 'a'
 103     fd = FileDict(data)
 104     times3 = test(fd, k, 5000)
 105     print
 106 
 107     import numpy as np
 108     import matplotlib.pyplot as plt
 109     ind = np.arange(4)
 110     p1 = plt.bar(ind, times1, width=0.2, color='r')
 111     p2 = plt.bar(ind+0.2, times2, width=0.2, color='g')
 112     p3 = plt.bar(ind+0.4, times3, width=0.2, color='b')
 113     
 114     plt.xticks(ind, ('method 1', 'method 2', 'method 3', 'method 4') )
 115     plt.legend( (p1[0], p2[0], p3[0]), ('hit', 'not hit', 'IO') )
 116 
 117     plt.show()
 118 
 119 class FileDict:
 120     def __init__(self, data):
 121         open('temp.txt','w').write(json.dumps(data))
 122 
 123     def get(self, key):
 124         return json.load(open('temp.txt'))[key]
 125     __getitem__ = get
 126 
 127     def has_key(self, key):
 128         return json.load(open('temp.txt')).has_key(key)
 129     __contains__ = has_key
 130 
 131 if __name__=="__main__":
 132     main()

结果如图(ubuntu9.10 + python2.6):


反馈

创建 by -- ZoomQuiet [2010-05-31 03:46:44]

MiscItems/2010-05-31 (last edited 2010-05-31 03:46:44 by ZoomQuiet)