17

I usually use the following idiom when working with a Python dictionary:

try:
    val = dct[key]
except KeyError:
    print key, " is not valid"

since for large dictionaries, the statement

if key in dct:
    # do something

is not very efficient (so I remember reading, but I've noticed it in practice as well)

Today I was working with a defaultdict and for a moment I forgot that a defaultdict will never give you a KeyError but instead will update the original dictionary.

How can I perform a lookup without updating the defaultdict? I really need to print an error so that the user can reenter the key.

Thank you!

UPDATE: Several posters suggested that my belief that if key in dct: is slow is false. I went back and checked the book in which I had read that is better to use try: except:. It is 2002's Python Cookbook, Recipe 1.4 by Alex Martelli, which can be found also online here: Add an entry to dictionary. Old memories are so unreliable! The recipe doesn't mention "slower" and it's not even using in but has_key. It simply says that try: except: is more Pythonic (at least the book version of the recipe). Thanks for the correction and the answers.

Óscar López
  • 215,818
  • 33
  • 288
  • 367
Lejlek
  • 754
  • 3
  • 8
  • 15
  • Possible duplicate http://stackoverflow.com/questions/1602934/what-is-a-good-way-to-test-if-a-key-exists-in-python-dictionary – Abhijeet Rastogi Jan 28 '12 at 17:40
  • 1
    Not a dupe; this one's about `defaultdict`. – Fred Foo Jan 28 '12 at 17:42
  • 7
    `key in d` is not slow, period. If you say otherwise, you better have solid proof. `timeit` says it's as fast as a successful `d[key]`, and much (nearly 10x) faster than a `d[key]` + `except: pass` (granted, it may be slightly faster than an explicit `if` if the key is nearly always present). Now, `key in d.keys()` (Python 2.x) or `key in list(d.keys())` (Python 3.x) is slow, but that because it's deliberately throwing away the hash table information. –  Jan 28 '12 at 17:50
  • 1
    **Must see** [this answer](http://stackoverflow.com/a/13465745/832230). – Acumenus Oct 30 '16 at 05:56

2 Answers2

24

How can I perform a lookup without updating the defaultdict?

With key in dct, i.e. explicitly.

If this is really too expensive for you (measure and you'll be sure), there are workarounds for specific situations. E.g., if your default value is 'ham' and in some situations you don't want to store (key, 'ham') in the defaultdict when key is not found, you can do

dct.get(key, 'ham')  # will return dct[key] or 'ham' but never stores anything
Fred Foo
  • 328,932
  • 68
  • 689
  • 800
  • 9
    `has_key` is deprecated in favor of `key in dct` - please do not promote the use of old idioms. – PaulMcG Jan 28 '12 at 19:10
9

key in dct has to be fast, saying that is slow would be like saying that dct[key] is slow, and that must never be the case. Retrieving an element from a dictionary given its key and testing membership of a key have to be O(1) operations in any decent dictionary implementation, and it's easy to see how the membership operation could be implemented in terms of the access operation.

For your question with defaultdict, just use in. And there's no reason for avoiding the use of in in a normal dictionary.

Óscar López
  • 215,818
  • 33
  • 288
  • 367