`if key in dict` vs. `try/except` - which is more readable idiom?
我有一个关于习语和可读性的问题,对于这个特定的案例,似乎有一个与Python哲学的冲突:
我想从字典B构建字典A。如果B中不存在特定的键,则不执行任何操作并继续。
哪条路更好?
1 2 3 4 | try: A["blah"] = B["blah"] except KeyError: pass |
或
1 2 | if"blah" in B: A["blah"] = B["blah"] |
"做并请求宽恕"与"简单和直率"。
哪个更好,为什么?
例外不是条件。
有条件的版本更清晰。这是很自然的:这是直接的流控制,这是设计条件的目的,而不是例外。
异常版本主要用作在循环中进行这些查找时的优化:对于某些算法,它允许从内部循环中消除测试。这里没有这种好处。它的一个小优点是它避免了说两次
一般来说,我强烈建议在默认情况下坚持使用条件版本,除非您有特定的理由不这样做。条件是实现这一点的明显方法,这通常是一种强烈的建议,即选择一种解决方案而不是另一种解决方案。
还有第三种方法可以避免出现异常和重复查找,如果查找成本很高,这一点很重要:
1 2 3 | value = B.get("blah", None) if value is None: A["blah"] = value |
如果您希望字典包含
1 2 3 4 5 | MyConst = object() def update_key(A, B, key): value = B.get(key, MyConst) if value is not MyConst: A[key] = value |
不管怎样,使用
1 | a.update((k, b[k]) for k in ("foo","bar","blah") if k in b) |
据我所知,您希望使用dict b中的键、值对更新dict a
1 | A.update(B) |
例子:
1 2 3 4 5 6 | >>> 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} >>> |
从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.
因此,根据具体情况,这两种选择似乎都是可行的。有关详细信息,请查看此链接:尝试性能除外
我认为第二个例子是,除非这段代码有意义,否则您应该选择:
1 2 3 4 5 6 | try: A["foo"] = B["foo"] A["bar"] = B["bar"] A["baz"] = B["baz"] except KeyError: pass |
记住,只要有一个键不在
当然,人们告诉你使用
1 2 | updateset = {'foo', 'bar', 'baz'} A.update({k: B[k] for k in updateset if k in B}) |
我认为这里的一般规则是:
我认为"尝试"在时间上是便宜的,但"例外"更贵。
其他语言的规则是为特殊情况保留例外,即在正常使用中不会发生的错误。不知道该规则如何应用于Python,因为该规则不应该存在stopIteration。
就我个人而言,我倾向于第二种方法(但使用
1 2 | if B.has_key("blah"): A["blah"] = B["blah"] |
这样,每个分配操作只有两行(而不是4行,带有try/except),任何抛出的异常都将是真正的错误或您遗漏的东西(而不是仅仅尝试访问不存在的键)。
事实证明(见对你问题的评论),
1 2 | if"blah" in B: A["blah"] = B["blah"] |
启动
1 2 3 4 5 | # dictB = {'hello': 5, 'world': 42} # dictA = {} if value := dictB.get('hello', None): dictA["hello"] = value # dictA is now {'hello': 5} |
为什么不这么做:
1 2 3 4 5 6 7 | def try_except(x,col): try: return x[col] except: return None list(map(lambda x: try_except(x,'blah'),A)) |