Python best way to check for existing key
Which is the m开发者_运维问答ore efficient/faster/better way to check if a key exists?
if 'subject' in request.POST:
subject = request.POST['subject']
else:
// handle error
OR
try:
subject = request.POST['subject']
except KeyError:
// handle error
The latter (try/except
) form is generally the better form.
try
blocks are very cheap but catching an exception can be more expensive. A containment check on a dict tends to be cheap, but not cheaper than nothing. I suspect there will be a balance of efficiency depending on how often 'subject'
is really there. However, this doesn't matter, since premature optimization is useless, distracting, wasteful, and ineffective. You would go with the better solution.
If the code would actually be of the form
if 'subject' in request.POST:
subject = request.POST['subject']
else:
subject = some_default
then what you actually want is request.POST.get('subject', some_default)
.
I use .get() method — it is preferable method.
Python 2.5.2 (r252:60911, Jul 22 2009, 15:33:10)
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import dis
>>> def f1(key, d):
... if key in d:
... return d[key]
... else:
... return "default"
...
>>> dis.dis(f1)
2 0 LOAD_FAST 0 (key)
3 LOAD_FAST 1 (d)
6 COMPARE_OP 6 (in)
9 JUMP_IF_FALSE 12 (to 24)
12 POP_TOP
3 13 LOAD_FAST 1 (d)
16 LOAD_FAST 0 (key)
19 BINARY_SUBSCR
20 RETURN_VALUE
21 JUMP_FORWARD 5 (to 29)
>> 24 POP_TOP
5 25 LOAD_CONST 1 ('default')
28 RETURN_VALUE
>> 29 LOAD_CONST 0 (None)
32 RETURN_VALUE
>>> def f2(key, d):
... return d.get(key, "default")
...
>>> dis.dis(f2)
2 0 LOAD_FAST 1 (d)
3 LOAD_ATTR 0 (get)
6 LOAD_FAST 0 (key)
9 LOAD_CONST 1 ('default')
12 CALL_FUNCTION 2
15 RETURN_VALUE
>>> def f3(key, d):
... try:
... return d[key]
... except KeyError:
... return "default"
...
>>> dis.dis(f3)
2 0 SETUP_EXCEPT 12 (to 15)
3 3 LOAD_FAST 1 (d)
6 LOAD_FAST 0 (key)
9 BINARY_SUBSCR
10 RETURN_VALUE
11 POP_BLOCK
12 JUMP_FORWARD 23 (to 38)
4 >> 15 DUP_TOP
16 LOAD_GLOBAL 0 (KeyError)
19 COMPARE_OP 10 (exception match)
22 JUMP_IF_FALSE 11 (to 36)
25 POP_TOP
26 POP_TOP
27 POP_TOP
28 POP_TOP
5 29 LOAD_CONST 1 ('default')
32 RETURN_VALUE
33 JUMP_FORWARD 2 (to 38)
>> 36 POP_TOP
37 END_FINALLY
>> 38 LOAD_CONST 0 (None)
41 RETURN_VALUE
Last time I checked, the first one is a few nanoseconds faster. But most phythonistas seem to favor the second one.
I think I'm not the only one that want to reserve exceptions for exceptional behavior, so I try to use the first one, reserving the second one when it's invalid not to have the key
The second will fail with collections.defaultdict
, and the exception will cause a small performance bump. Other than there there is no real difference between the two.
I think it depends on whether 'subject' not being in POST is actually an exception. If it is not supposed to happen but you are just being extra careful, then your second method would I assume be more efficient and quicker. However if you are using the check to do 1 thing or another then it is not appropriate to use an exception. From the look of your code, I would go with your second option.
I too like get() you can also specify a default value (other than none) in case that makes sense.
dict
and many dict-like objects (including Django's HttpRequest
you seem to be using) allow passing default value to get()
:
subject = request.POST.get('subject', '[some_default_subject]')
This is preferrable method as it is the shortest and most transparent about your intentions.
subject = request.POST.get("subject")
if subject is None:
...
:)
精彩评论