programing

`if key in dict` vs.`try / except`-어느 것이 더 읽기 쉬운 관용구입니까?

nasanasas 2020. 9. 14. 21:14
반응형

`if key in dict` vs.`try / except`-어느 것이 더 읽기 쉬운 관용구입니까?


관용구와 가독성에 대한 질문이 있는데,이 특별한 경우에 파이썬 철학이 충돌하는 것 같습니다.

사전 B에서 사전 A를 만들고 싶습니다. 특정 키가 B에 없으면 아무 작업도 수행하지 않고 계속합니다.

어느 쪽이 더 낫습니까?

try:
    A["blah"] = B["blah"]
except KeyError:
    pass

또는

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

"용서를 구하고 구하라"대 "단순함과 명료 함".

어느 것이 더 낫고 그 이유는 무엇입니까?


예외는 조건부가 아닙니다.

조건부 버전이 더 명확합니다. 이것은 당연합니다. 이것은 단순한 흐름 제어이며, 예외가 아니라 조건문을 위해 설계된 것입니다.

예외 버전은 주로 루프에서 이러한 조회를 수행 할 때 최적화로 사용됩니다. 일부 알고리즘의 경우 내부 루프에서 테스트를 제거 할 수 있습니다. 여기에는 그 혜택이 없습니다. "blah"두 번 말하지 않아도된다는 작은 장점이 있지만, 이런 일을 많이한다면 move_key어차피 도우미 기능 이있을 것 입니다.

일반적으로 특별한 이유가없는 한 기본적으로 조건부 버전을 사용하는 것이 좋습니다. 조건문은 이를 수행 하는 명백한 방법이며 일반적으로 한 솔루션을 다른 솔루션보다 선호하는 강력한 권장 사항입니다.


예외와 이중 조회를 모두 피하는 세 번째 방법도 있습니다. 조회 비용이 많이 드는 경우 중요 할 수 있습니다.

value = B.get("blah", None)
if value is None: 
    A["blah"] = value

경우에는 사전에 포함 할 것으로 예상 None당신이 좋아 좀 더 난해한 상수를 사용하여 값을 NotImplemented, Ellipsis또는 새로운 하나를 만들 :

MyConst = object()
def update_key(A, B, key):
    value = B.get(key, MyConst)
    if value is not MyConst: 
        A[key] = value

어쨌든 사용 update()은 나에게 가장 읽기 쉬운 옵션입니다.

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

내가 이해하는 바에 따르면 dict B의 키, 값 쌍으로 dict A를 업데이트하고 싶습니다.

update 더 나은 선택입니다.

A.update(B)

예:

>>> 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 성능 위키에서 직접 인용 :

처음을 제외하고는 단어를 볼 때마다 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


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

Though the accepted answer's emphasize on "look before you leap" principle might apply to most languages, more pythonic might be the first approach, based on the python principles. Not to mention it is a legitimate coding style in python. Important thing is to make sure you are using the try except block in the right context and is following best practices. Eg. doing too many things in a try block, catching a very broad exception, or worse- the bare except clause etc.

Easier to ask for forgiveness than permission. (EAFP)

See the python docs reference here.

Also, this blog from Brett, one of the core devs, touches most of this in brief.

See another SO discussion here:

참고URL : https://stackoverflow.com/questions/4512557/if-key-in-dict-vs-try-except-which-is-more-readable-idiom

반응형