This isn't premature optimization. My use case has the double-checking of dict's right in the inner-most of inner loops, running all the time. Also, it's intellectually irksome (see results).
Which of these approaches is faster?
mydict = { 'hello': 'yes', 'goodbye': 'no' }
key = 'hello'
# (A)
if key in mydict:
a = mydict[key]
do_things(a)
else:
handle_an_error()
# vs (B)
a = mydict.get(key,None)
if a is not None:
do_things(a)
else:
handle_an_error()
Edit: these are the same speed. Common sense tells me that (B) should be noticeably faster since it's only one dict lookup vs. 2, but the results are different. I'm scratching my head.
Results of a benchmark averaged over 12 runs, 1/2 of which are hits, the other half are misses:
doing in
switching to get
total time for IN: 0.532250006994
total time for GET: 0.480916659037
times found: 12000000
times not found: 12000000
And when a similar one is run (*10 more loops) without ever finding the key,
doing in
switching to get
total time for IN: 2.35899998744
total time for GET: 4.13858334223
Why!?
(correct) code
import time
smalldict = {}
for i in range(10):
smalldict[str(i*4)] = str(i*18)
smalldict["8"] = "hello"
bigdict = {}
for i in range(10000):
bigdict[str(i*100)] = str(i*4123)
bigdict["hello"] = "yes!"
timetotal = 0
totalin = 0
totalget = 0
key = "hello"
found= 0
notfound = 0
ddo = bigdict # change to smalldict for small dict gets
print 'doing in'
for r in range(12):
start = time.time()
a = r % 2
for i in range(1000000):
if a == 0:
if str(key) in ddo:
found = found + 1
foo = ddo[str(key)]
else:
notfound = notfound + 1
foo = "nooo"
else:
if 'yo' in ddo:
found = found + 1
foo = ddo['yo']
else:
notfound = notfound + 1
foo = "nooo"
timetotal = timetotal + (time.time() - start)
totalin = timetotal / 12.0
print 'switching to get'
timetotal = 0
for r in range(12):
start = time.time()
a = r % 2
for i in range(1000000):
if a == 0:
foo = ddo.get(key,None)
if foo is not None:
found = found + 1
else:
notfound = notfound + 1
foo = "nooo"
else:
foo = ddo.get('yo',None)
if foo is not None:
found = found + 1
notfound = notfound + 1
else:
notfound = notfound + 1
foo = "oooo"
timetotal = timetotal + (time.time() - start)
totalget = timetotal / 12
print "total time for IN: ", totalin
print 'total time for GET: ', totalget
print 'times found:', found
print 'times not found:', notfound
(original) code import time smalldict = {} for i in range(10): smalldict[str(i*4)] = str(i*18)
smalldict["8"] = "hello"
bigdict = {}
for i in range(10000):
bigdict[str(i*100)] = str(i*4123)
bigdict["8000"] = "hello"
timetotal = 0
totalin = 0
totalget = 0
key = "hello"
found= 0
notfound = 0
ddo = bigdict # change to smalldict for small dict gets
print 'doing in'
for r in range(12):
start = time.time()
a = r % 2
for i in range(10000000):
if a == 0:
if key in ddo:
foo = ddo[key]
else:
foo = "nooo"
else:
if 'yo' in ddo:
foo = ddo['yo']
else:
foo = "nooo"
timetotal = timetotal + (time.time() - start)
totalin = timetotal / 12.0
print 'switching to get'
timetotal = 0
for r in range(12):
start = time.time()
a = r % 2
for i in range(10000000):
if a == 0:
foo = ddo.get(key,None)
if foo is not None:
# yaaay
pass
else:
foo = "nooo"
else:
foo = ddo.get('yo',None)
if foo is not None:
#yaaay
pass
else:
foo = "oooo"
timetotal = timetotal + (time.time() - start)
totalget = timetotal / 12
print "total time for IN: ", totalin
print 'total time for GET: ', totalget