Python- 'dict in dict'vs 'try : dict [foo]'


24

이것은 오리 타이핑의 본질에 대한 질문이 아니며 파이 토닉을 유지하는 것에 관한 더 많은 것입니다.

우선 dicts를 다룰 때, 특히 dict의 구조가 상당히 예측 가능하고 주어진 키가 일반적으로 존재 하지 않지만 때로는 존재하는 경우 두 가지 접근법을 먼저 생각합니다.

if myKey in dict:
    do_some_work(dict[myKey])
else:
    pass

그리고 물론 예 올데의 '용서와 허가'접근.

try:
    do_some_work(dict[myKey])
except KeyError:
    pass

여행사 파이썬 사람으로서, 나는 후자가 많이 선호하는 것을 느낍니다. 파이썬 문서 try/excepts에서는 실제 실수가있을 때 선호되는 것처럼 보이기 때문에 이상하게 생각합니다 .

가끔 dict에 myDict에 키 가없고 항상 해당 키 가있는 것은 아니라는 것이 문맥 상 오도적인 시도 / 제외입니까? 이것은 프로그래밍 오류가 아니라 데이터의 사실 일뿐입니다.이 지시에는 특정 키가 없었습니다.

try / except / else 구문을 볼 때 특히 중요해 보입니다. try / except / else 구문은 try가 너무 많은 오류를 포착하지 않도록하는 데 매우 유용합니다. 다음과 같은 작업을 수행 할 수 있습니다.

try:
    foo += bar
except TypeError:
    pass
else:
    return some_more_work(foo)

그렇게하면 코드가 잘못되어 모든 종류의 이상한 오류를 삼키지 않을 것입니까? 위의 코드는 추가하려는 것을 보지 2 + {}못하고 코드의 일부가 잘못되었다는 것을 결코 깨닫지 못할 수도 있습니다. 모든 유형을 확인해야한다고 제안하지는 않습니다. 그래서 JavaScript가 아닌 Python이기 때문에 시도 / 제외와 관련하여 다시해서는 안되는 일을하는 프로그램을 잡는 것으로 보입니다. 계속해서

위의 예는 밀짚 맨 논쟁의 일부이며 실제로 의도적으로 나쁘다는 것을 알고 있습니다. 그러나 pythonic creed의 better to ask forgiveness than permission도움을 줄 수는 없지만 모래의 선이 실제로 if / else와 try / except의 올바른 적용 사이, 특히 당신이 무엇을 기대 해야하는지 알 때 작업중인 데이터

나는 여기서 속도 문제 또는 모범 사례에 대해 이야기하지 않고, 어느 방향 으로든 갈 수있는 것으로 보이는 벤 다이어그램에 의해 조용히 혼란스러워하지만 사람들은 시도 / 제외 측면에서 실수합니다. 왜냐하면 '어딘가 누군가가 파이썬 적이라고 말했기 때문입니다.' 이 구문의 적용에 대한 잘못된 결론을 도출 했습니까?

python 

시도 제외 경향이 오류를 숨길 위험이 있음에 동의합니다. 내 의견은 일반적으로 예상되는 조건을 제외하고 시도를 피해야한다는 것입니다 (물론이 규칙에는 예외가 있습니다).
고든 빈

답변:


26

get 메소드를 대신 사용하십시오 .

some_dict.get(the_key, default_value)

... 이 아닌 default_value경우 반환되는 값 the_key입니다 some_dict. 생략하면 default_value, None키가없는 경우 반환됩니다.

일반적으로 파이썬에서는 사람들이 먼저 무언가를 확인하는 것보다 시도 / 제외를 선호하는 경향이 있습니다. 용어집 에서 EAFP 항목을 참조하십시오 . 많은 "멤버쉽 테스트"기능은 배후에서 예외를 사용합니다.


그래도 이런 종류의 문제가 아닌가? 우리가 dict발견 한 것을 기반으로 작업하고 노력하고 있다면 , 더 if myDict.get(a_key) is not None: do_work(myDict[a_key])뛰어나고 뛰어 나기 전에 암묵적으로 보이는 또 다른 예가 있습니다. 아마도 dict.get(a_key, a_default)올바른 맥락에서 이해하지 못하지만 '스위치가 아닌 경우 if / elses'나 마법의 가치를 쓰는 것의 전조 인 것처럼 보입니다. 나는이 방법이 무엇을 좋아하는지, 더 자세히 살펴볼 것입니다.

1
@Stick-당신은 : data = myDict.get(a_key, default)그리고 do_work주어진 default(예를 들어 None) 당신이 할 때 올바른 일을 할 것 if data: do_work(data)입니다. 두 경우 모두 하나의 조회 만 필요했습니다. ( if data is not None: ...어쨌든 검색은 여전히 ​​하나의 조회 일 뿐이고 사용자 자신의 논리가 대신 할 수 있습니다.)
detly

1
그래서 dict.get ()이 현재 프로젝트에서 많은 노력을 절약했다고 ​​결정했습니다. 줄 수를 줄이고 많은 끔찍한 try/except/else정크를 정리했으며 IMHO의 코드 가독성을 전반적으로 개선했습니다. 나는 전에 들어 본 귀중한 교훈을 배웠지 만, 너무 많은 코드를 작성하고 있다고 생각되면 언어 기능을 멈추고 살펴보십시오. 감사!!

@Stick-들어서 기쁘다 :) 나는 그 조언을 좋아한다.
detly

1
기술적으로 가장 빠른 것은 무엇입니까?
Olivier Pons

4

키가 규칙이나 예외 입니까?

실용적인 관점에서 던지기 / 잡기는 속도가 훨씬 느리고 키가 테이블에 있는지 확인합니다. 누락 된 키가 일반적인 경우-조건을 사용해야합니다.

상태를 선호하는 또 다른 것은 else 절입니다. 블록이 실행될 경우 어느 블록이 실행되는지 이해하기가 훨씬 쉬우 며 try 블록의 여러 명령문에서 동일한 예외 클래스가 발생할 수 있다는 점을 고려하십시오.

except 절의 코드 는 일반적인 결함의 일부가 아니어야합니다 (예 : 키가 없으면 추가)-오류를 처리해야합니다.


4
"실용적인 관점에서 볼 때 던지기 / 잡기는 속도가 훨씬 느리고 키가 테이블에 있는지 확인합니다." 반드시 그런 것은 아닙니다. 마지막으로, 가장 일반적인 Python 구현은 try/ catch버전을 더 빠르게 수행합니다 .
detly

2
파이썬에서 throw / catch는 파이썬에서 흐름 제어에 자주 사용되는 정도로 현명한 성능은 아닙니다. 또한 테스트와 액세스 사이에서 dict을 수정할 수있는 상황이있을 수 있습니다.
whatsisname

@whatsisname-나는 그것을 내 대답에 추가 할 생각을했지만 TBH 만약 당신이 그런 경주 위험이 있다면 EAFP 대 LBYL : P
detly

1

"pythonic", 특히 오리 타이핑이라는 정신으로, 시도 / 제외는 거의 연약 해 보입니다.

당신이 정말로 원하는 것은 dict-like 액세스를 가진 것이지만, __getitem__당신이 기대하지 않은 것을하기 위해 재정의 될 수 있습니다. 예를 들어 defaultdict표준 라이브러리에서 사용 하는 경우 :

In [1]: from collections import defaultdict

In [2]: foo = defaultdict(int)

In [3]: foo['a'] = 1

In [4]: foo['b']  # Someone did access checking with a try/except exactly as you have in the question
Out[4]: 0

In [5]: 'a' in foo
Out[5]: True

In [6]: 'b' in foo  # We never set it, but now it exists!
Out[6]: True

In [7]: 'c' in foo
Out[7]: False

기본 반환 값은 Falsy이므로 이와 같은 액세스 검사는 대부분의 경우 정상적으로 작동합니다. 코드를 더 단순하게 유지하는 것처럼 보였으므로 동료와 몇 달 동안 수행했습니다.

불행히도, 몇 달 후, 이러한 추가 키는 실제로 문제가되고 추적하기 어려운 버그를 일으켰습니다 0. 그리고 때때로 우리는 것이다 사용 in이 동일한 있었어야 할 때 코드가 다른 일을하고, 키가 존재하는지 확인 할 수 있습니다.

내가 깨진 것처럼 보이는 이유는 파이썬의 오리 타이핑 정신에서 원하는 것은 dict-like와 같으며 defaultdict생성 할 수있는 객체와 마찬가지로 요구 사항에 완벽하게 부합하기 때문입니다.dict . 호출자가 나중에 회선의 구현을 변경하지 않을 것이라고 보장 할 수 없으므로 부작용이 가장 적은 작업을 수행해야합니다.

첫 번째 버전을 사용하십시오 if myKey in mydict.


또한 이것은 특별히 질문의 예에 관한 것입니다. "권한보다 용서를 구하는 것이 더 좋다"는 파이썬 신념은 주로 원하는 것을 얻지 못할 때 실제로 올바르게 행동하도록하기위한 것입니다. 예를 들어, 파일이 존재하는지 확인한 다음 파일을 읽으려고 시도하면 적어도 3 가지가 맨 윗부분에서 잘못 생각할 수 있습니다.

  • 경쟁 조건은 파일이 삭제 / 이동 / 등화되었을 수 있다는 것입니다.
  • 파일에 대한 읽기 권한이 없습니다
  • 파일이 손상되었습니다

첫 번째 것은 "허가 요청"을 시도 할 수 있지만 경쟁 조건의 특성상 반드시 항상 작동하는 것은 아닙니다. 두 번째는 너무 잊어 버리기 쉽다. 파일을 읽지 않으면 세 번째를 확인할 수 없습니다 . 어떤 경우에는, 당신은 거의 확실히 그렇게에서 동일하다 실패한 후하는 일 예를 들어, 그것은 이다 제외시켰다 / 시도를 사용하여 "용서를 물어"더 나은.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.