开发者

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:
   ...

:)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜