Python `if key in dict` 与 `try/except` - 哪个更易读?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4512557/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 16:04:49  来源:igfitidea点击:

`if key in dict` vs. `try/except` - which is more readable idiom?

pythonidiomsreadabilitydefaultdictcode-readability

提问by LeeMobile

I have a question about idioms and readability, and there seems to be a clash of Python philosophies for this particular case:

我有一个关于习语和可读性的问题,对于这种特殊情况,Python 哲学似乎存在冲突:

I want to build dictionary A from dictionary B. If a specific key does not exist in B, then do nothing and continue on.

我想从字典 B 构建字典 A。如果 B 中不存在特定键,那么什么都不做并继续。

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?

哪个更好?为什么?

采纳答案by Glenn Maynard

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_keyfunction anyway.

在循环中进行这些查找时,异常版本主要用作优化:对于某些算法,它允许从内部循环中消除测试。它在这里没有那个好处。它有一个小优势,它避免了重复"blah"两次,但如果你做了很多这样的事情,你可能move_key无论如何都应该有一个辅助函数。

In general, I'd strongly recommend sticking with the conditional version by default unless you have a specific reason not to. Conditionals are the obviousway to do this, which is usually a strong recommendation to prefer one solution over another.

一般来说,我强烈建议默认情况下坚持使用条件版本,除非您有特定的理由不这样做。条件语句是执行此操作的显而易见的方法,通常强烈建议优先选择一种解决方案而不是另一种解决方案。

回答by pyfunc

From what I understand, you want to update dict A with key,value pairs from dict B

据我了解,您想使用 dict B 中的键值对更新 dict A

updateis a better choice.

update是更好的选择。

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}
>>> 

回答by girasquid

Personally, I lean towards the second method (but using has_key):

就个人而言,我倾向于第二种方法(但使用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).

这样,每个赋值操作只有两行(而不是 4 行,try/except),并且抛出的任何异常都将是真正的错误或您遗漏的东西(而不是仅仅尝试访问不存在的键) .

As it turns out (see the comments on your question), has_keyis deprecated - so I guess it's better written as

事实证明(请参阅对您的问题的评论)has_key已被弃用 - 所以我想最好写成

if "blah" in B:
  A["blah"] = B["blah"]

回答by neil

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:

我认为这里的一般规则A["blah"]通常会存在,如果是这样,try-except 是好的,如果不是,则使用if "blah" in b:

I think "try" is cheap in time but "except" is more expensive.

我认为“尝试”及时便宜但“除外”更贵。

回答by Mark Ransom

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.

其他语言的规则是为异常情况保留例外,即在常规使用中不会发生的错误。不知道该规则如何应用于 Python,因为该规则不应该存在 StopIteration。

回答by Omnifarious

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.

请记住,只要存在不在B. 如果这段代码有意义,那么你应该使用异常方法,否则使用测试方法。在我看来,因为它更短并且清楚地表达了意图,所以它比异常方法更容易阅读。

Of course, the people telling you to use updateare correct. If you are using a version of Python that supports dictionary comprehensions, I would strongly prefer this code:

当然,告诉你使用的人update是正确的。如果您使用的是支持字典推导式的 Python 版本,我强烈希望使用以下代码:

updateset = {'foo', 'bar', 'baz'}
A.update({k: B[k] for k in updateset if k in B})

回答by lqc

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 not None: 
    A["blah"] = value

In case you expect the dictionary to contain Nonevalues, you can use some more esoteric constants like NotImplemented, Ellipsisor make a new one:

如果您希望字典包含None值,您可以使用一些更深奥的常量,例如NotImplementedEllipsis或者创建一个新常量:

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:

无论如何,使用update()对我来说是最易读的选项:

a.update((k, b[k]) for k in ("foo", "bar", "blah") if k in b)

回答by Sami Lehtinen

Direct quote from Python performance wiki:

直接引用 Python 性能 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.

除了第一次,每次看到一个单词时,if 语句的测试都会失败。如果您计算大量单词,许多单词可能会出现多次。在一个值的初始化只会发生一次并且该值的增加将发生多次的情况下,使用 try 语句会更便宜。

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

因此,根据情况,这两种选择似乎都是可行的。有关更多详细信息,您可能想查看此链接:Try-except-performance

回答by Nico Coallier

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))

回答by Xavier Guihot

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

开始Python 3.8,并引入赋值表达式(PEP 572):=运算符),我们可以捕获dictB.get('hello', None)变量value中的条件值,以便检查它是否不是None(作为dict.get('hello', None)返回关联值或None),然后在条件:

# dictB = {'hello': 5, 'world': 42}
# dictA = {}
if value := dictB.get('hello', None):
  dictA["hello"] = value
# dictA is now {'hello': 5}