I have a question about idioms and readability, and there seems to be a clash of Python philosophies for this particular case:
I want to build dictionary A from dictionary B. If a specific key does not exist in B, then do nothing and continue on.
Which way is better?
try:
A["blah"] = B["blah"]
except KeyError:
pass
or
if "blah" in B:
A["blah"] = B["blah"]
"Do and ask for forgiveness" vs. "simplicity and explicitness".
Which is better and why?
Exceptions are not conditionals.
The conditional version is clearer. That's natural: this is straightforward flow control, which is what conditionals are designed for, not exceptions.
The exception version is primarily used as an optimization when doing these lookups in a loop: for some algorithms it allows eliminating tests from inner loops. It doesn't have that benefit here. It has the small advantage that it avoids having to say "blah"
twice, but if you're doing a lot of these you should probably have a helper move_key
function anyway.
In general, I'd strongly recommend sticking with the conditional version by default unless you have a specific reason not to. Conditionals are the obvious way to do this, which is usually a strong recommendation to prefer one solution over another.
There is also a third way that avoids both exceptions and double-lookup, which can be important if the lookup is expensive:
value = B.get("blah", None)
if value is None:
A["blah"] = value
In case you expect the dictionary to contain None
values, you can use some more esoteric constants like NotImplemented
, Ellipsis
or make a new one:
MyConst = object()
def update_key(A, B, key):
value = B.get(key, MyConst)
if value is not MyConst:
A[key] = value
Anyway, using update()
is the most readable option for me:
a.update((k, b[k]) for k in ("foo", "bar", "blah") if k in b)
From what I understand, you want to update dict A with key,value pairs from dict B
update
is a better choice.
A.update(B)
Example:
>>> A = {'a':1, 'b': 2, 'c':3}
>>> B = {'d': 2, 'b':5, 'c': 4}
>>> A.update(B)
>>> A
{'a': 1, 'c': 4, 'b': 5, 'd': 2}
>>>
Direct quote from Python performance wiki:
Except for the first time, each time a word is seen the if statement's test fails. If you are counting a large number of words, many will probably occur multiple times. In a situation where the initialization of a value is only going to occur once and the augmentation of that value will occur many times it is cheaper to use a try statement.
So it seems that both options are viable depending from situation. For more details you might like to check this link out: Try-except-performance
I think the general rule here is will A["blah"]
normally exist, if so try-except is good if not then use if "blah" in b:
I think "try" is cheap in time but "except" is more expensive.
I think the second example is what you should go for unless this code makes sense:
try:
A["foo"] = B["foo"]
A["bar"] = B["bar"]
A["baz"] = B["baz"]
except KeyError:
pass
Keep in mind that code will abort as soon as there is a key that isn't in B
. If this code makes sense, then you should use the exception method, otherwise use the test method. In my opinion, because it's shorter and clearly expresses the intent, it's a lot easier to read than the exception method.
Of course, the people telling you to use update
are correct. If you are using a version of Python that supports dictionary comprehensions, I would strongly prefer this code:
updateset = {'foo', 'bar', 'baz'}
A.update({k: B[k] for k in updateset if k in B})
The rule in other languages is to reserve exceptions for exceptional conditions, i.e. errors that don't occur in regular use. Don't know how that rule applies to Python, as StopIteration shouldn't exist by that rule.
Personally, I lean towards the second method (but using has_key
):
if B.has_key("blah"):
A["blah"] = B["blah"]
That way, each assignment operation is only two lines (instead of 4 with try/except), and any exceptions that get thrown will be real errors or things you've missed (instead of just trying to access keys that aren't there).
As it turns out (see the comments on your question), has_key
is deprecated - so I guess it's better written as
if "blah" in B:
A["blah"] = B["blah"]
Starting Python 3.8
, and the introduction of assignment expressions (PEP 572) (:=
operator), we can capture the condition value dictB.get('hello', None)
in a variable value
in order to both check if it's not None
(as dict.get('hello', None)
returns either the associated value or None
) and then use it within the body of the condition:
# dictB = {'hello': 5, 'world': 42}
# dictA = {}
if value := dictB.get('hello', None):
dictA["hello"] = value
# dictA is now {'hello': 5}
Why not just do this :
def try_except(x,col):
try:
return x[col]
except:
return None
list(map(lambda x: try_except(x,'blah'),A))
来源:https://stackoverflow.com/questions/4512557/if-key-in-dict-vs-try-except-which-is-more-readable-idiom