Reputation: 425
So, say there is a dictionary var_dict
, and I want to print the value at a key a
for eg.
So, one way would be:
if var_dict is None:
return
if 'a' not in var_dict.keys():
return
print(var_dict['a'])
And other method would be:
try:
print(var_dict['a'])
except (KeyError, TypeError):
return
My question is which is recommended. I read here: Python: try-except vs if-else to check dict keys , that exception handling is slower but what if we specify the expected error? Is it slow in that case as well?
Upvotes: 0
Views: 515
Reputation: 149
Use the second method. From the Python Glossary:
EAFP:
Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C.
Just to be sure, I just tried both using the %%timeit magic command in jupyter and the second option is slightly faster.
Upvotes: 0
Reputation: 1055
A try/except
block to retrieve a key or a default will be much faster than all other alternatives. E.g.
from time import time
t = time()
for i in range(1000000):
v = __builtins__['int'] if 'int' in __builtins__ else None
print(time() - t)
t = time()
for i in range(1000000):
v = __builtins__.get('int', None)
print(time() - t)
t = time()
for i in range(1000000):
try:
v = __builtins__['int']
except KeyError:
v = None
print(time() - t)
Results:
0.12224698066711426
0.15873217582702637
0.0927286148071289
The first one is much slower, because Python basically retrieve the key twice. Once through __contains__
, then __getitem__
. The second is slower because Python does some internal validation while the try/catch
goes straight to the point or fail.
Easier to ask for forgiveness than permission.
Upvotes: 2
Reputation: 13140
A try/except block is indeed slower. I'd do this:
def foobar(var_dict):
return var_dict['a'] if var_dict and 'a' in var_dict else None
Eg:
In [1]: def foobar(var_dict):
...: return var_dict['a'] if var_dict and 'a' in var_dict else None
...:
In [2]:
In [2]: foobar(None)
In [3]: foobar({'x': 1})
In [4]: foobar({'a': 1})
Out[4]: 1
Alternatively, if you know var_dict is a dictionary (and not None), get()
has a default:
return var_dict.get('a', None)
Upvotes: 3