Michel Keijzers
Michel Keijzers

Reputation: 15367

Python if/elseif construction as dictionary

In Python I use regularly the following construct:

x = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
y = x[v] if v in x.keys() else None

where v is normally one of the dictionary values, and y gets the value of the dictionary if the key exists, otherwise None.

I was wondering if this is a desired construct or if it can be enhanced?

x[v] can be values as above, but I also use a similar construct to call a function depending on the value of v, like:

{'a': self.f1, 'b': self.f2, 'c': self.f3, 'd': self.f4}[v]()

Upvotes: 0

Views: 265

Answers (3)

Aya
Aya

Reputation: 41950

After spending many hours profiling some similar code, I found the most efficient way to do this is to use defaultdict...

from collections import defaultdict

x = defaultdict(lambda: None, {'a': 1, 'b': 2, 'c': 3, 'd': 4})
y = x[v]

...and the next most efficient is two key lookups...

x = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
y = x[v] if x in v else None

Both of these are much faster than this...

x = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
y = x.get(v, None)

...and this...

x = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
try:
    y = x[v]
except KeyError:
    y = None

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1122352

Normally you'd use dict.get():

y = x.get(v)

.get() takes a default parameter to return if v is not present in the dictionary, but if you omit it None is returned.

Even if you were to use an explicit key test, you don't need to use .keys():

y = x[v] if v in x else None

Interestingly enough, the conditional expression option is slightly faster:

>>> [x.get(v) for v in 'acxz']  # demonstration of the test; two hits, two misses
[1, 3, None, None]
>>> timeit.timeit("for v in 'acxz': x.get(v)", 'from __main__ import x')
0.8269917964935303
>>> timeit.timeit("for v in 'acxz': x[v] if v in x else None", 'from __main__ import x')
0.67330002784729

until you avoid the attribute lookup for .get():

>>> timeit.timeit("for v in 'acxz': get(v)", 'from __main__ import x; get = x.get')
0.6585619449615479

so if speed matters, store a reference to the .get() method (note the get = x.get assignment).

Upvotes: 6

Inbar Rose
Inbar Rose

Reputation: 43457

What you have described can be said like this:

"y should be the value of key "v" if "v" exists in the dictionary, else it should be "none"

In Python, that is:

y = x.get(v, None)

Note: None is already the default return value when the key is not present.


In your question, you also mention that sometimes your dictionaries contain references to methods. In this case, y would then be the method if it is not None and you can call it normally:

y(*args, **kwargs)

Or like in your example:

{'a': self.f1, 'b': self.f2, 'c': self.f3, 'd': self.f4}.get(v)()

Note: that if the key is not in the dictionary, then it will raise a TypeError

Upvotes: 2

Related Questions