목록 이해에서 예외를 처리하는 방법은 무엇입니까?


120

파이썬에서 각 반복이 예외를 던질 수있는 목록 이해력이 있습니다.

예를 들어 다음 과 같은 경우 :

eggs = (1,3,0,3,2)

[1/egg for egg in eggs]

ZeroDivisionError번째 요소에서 예외가 발생합니다.

이 예외를 처리하고 목록 이해를 계속 실행하려면 어떻게해야합니까?

내가 생각할 수있는 유일한 방법은 도우미 기능을 사용하는 것입니다.

def spam(egg):
    try:
        return 1/egg
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

그러나 이것은 나에게 약간 성가신 것 같습니다.

Python에서이 작업을 수행하는 더 좋은 방법이 있습니까?

참고 : 이것은 ( "를 참조 간단한 예입니다 예를 들어 내 진짜 예를 몇 가지 문맥을 필요로하기 때문에 내가 고안하는 것이 위의"). 0으로 나누는 오류를 피하는 데 관심이 없지만 목록 이해에서 예외를 처리하는 데 관심이 있습니다.


4
있다 PEP 463 핸들 예외 표현식을 추가 할 수는. 귀하의 예에서는 [1/egg except ZeroDivisionError: None for egg in (1,3,0,3,2)]. 그러나 여전히 초안 모드입니다. 내 직감은 그것이 받아 들여지지 않을 것이라는 것입니다. Imho 표현식은 너무 복잡해질 수 있습니다 (여러 예외 확인, 더 복잡한 조합 (여러 논리 연산자, 복잡한 이해 등))
cfi

1
특정 예제의 경우 ndarray에서 적절한 설정으로 numpy 를 사용할 수 있습니다 np.seterr. 그 결과 1/0 = nan. 그러나 나는 이것이 필요가 발생하는 다른 상황으로 일반화되지 않는다는 것을 알고 있습니다.
gerrit

답변:


96

파이썬에는 예외를 무시 (또는 예외의 경우 대체 값 & c 반환) 할 수있는 내장 표현식이 없으므로, 목록 이해가 표현식이므로 문자 그대로 "목록 이해에서 예외 처리"가 불가능합니다. 다른 표현을 포함하고 그 이상은 없습니다 (예 : 문이 없고 문만 예외를 포착 / 무시 / 처리 할 수 ​​있음).

함수 호출은 표현식이며 함수 본문은 원하는 모든 문을 포함 할 수 있으므로 예외가 발생하기 쉬운 하위 표현식의 평가를 함수에 위임하는 것이 가능한 해결 방법 중 하나입니다 (가능한 경우 다른 방법은 다음과 같습니다. 다른 답변에서도 제안 된 것처럼 예외를 유발할 수있는 값을 확인합니다.

"목록 이해에서 예외를 처리하는 방법"이라는 질문에 대한 정답은 모두이 모든 진실의 일부를 표현하는 것입니다. 1) 문자 그대로, 즉 이해 자체에서 어휘 적으로는 할 수 없습니다. 2) 실제로 작업을 함수에 위임하거나 가능한 경우 오류가 발생하기 쉬운 값을 확인합니다. 이것이 답이 아니라는 당신의 반복적 인 주장은 근거가 없습니다.


14
내가 참조. 따라서 완전한 대답은 다음 중 하나를 수행해야한다는 것입니다. 1. 함수를 사용하십시오. 2. 목록 이해력을 사용하지 마십시오. 3. 예외를 처리하기보다는 방지하려고 노력하십시오.
Nathan Fellman

9
"목록 이해에서 예외를 처리하는 방법"에 대한 답변의 일부로 "목록 이해를 사용하지 않음"을 보지 못합니다.하지만 LC에서 어휘 적 으로 ""의 가능한 결과로 볼 수있을 것 같습니다. 예외 처리 "는 실제로 문자 그대로 대답의 첫 번째 부분입니다.
Alex Martelli

생성기 표현식 또는 생성기 이해에서 오류를 포착 할 수 있습니까?

1
@AlexMartelli, except 절이 미래의 파이썬 버전에서 작업하기가 그렇게 어려울까요? [x[1] for x in list except IndexError pass]. 인터프리터가 시도 할 임시 기능을 만들 수 x[1]없습니까?
alancalvitti

위의 @Nathan, 1,2,3은 기능적 데이터 흐름에서 엄청난 골칫거리가됩니다. 1. 일반적으로 람다를 통해 함수를 인라인하기를 원합니다. 2. 대안은 기능적 패러다임을 위반하고 오류가 발생하기 쉬운 코드로 이어지는 중첩 된 for 루프를 많이 사용하는 것입니다. 3. 종종 오류는 데이터에 대한 라틴어 단어가 의미하는 바와 같이, 쉽게 예방할 수없는 임시적이고 잠재적 인 복잡한 데이터 셋입니다.
alancalvitti

118

나는이 질문이 꽤 오래되었다는 것을 알고 있지만, 이런 종류의 일을 더 쉽게하기 위해 일반적인 함수를 만들 수도 있습니다.

def catch(func, handle=lambda e : e, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)

그런 다음 당신의 이해에서 :

eggs = (1,3,0,3,2)
[catch(lambda : 1/egg) for egg in eggs]
[1, 0, ('integer division or modulo by zero'), 0, 0]

물론 기본 핸들 기능을 원하는대로 만들 수 있습니다 (기본적으로 'None'을 반환하는 대신).

이 질문이 귀하 또는 향후 시청자에게 도움이되기를 바랍니다.

참고 : 파이썬 3에서는 'handle'인수 키워드 만 만들고 인수 목록 끝에 넣습니다. 이것은 실제로 인수를 전달하는 것과 같은 것을 catch를 통해 훨씬 더 자연스럽게 만듭니다.


2
매우 유용합니다. 감사합니다. 나는 이론적 의견에 동의하지만 이것은 내가 반복적으로 겪어 온 문제를 해결하는 실질적인 접근 방식을 보여줍니다.
Paul

2
훌륭한 대답. 내가 제안하는 한 가지 모드는 전달 args하고 kwargs처리하는 것입니다. 그렇게 egg하면 하드 코딩 된 대신 say 를 반환 0하거나 수행하는 예외를 반환 할 수 있습니다.
Mad Physicist

3
또한 예외 유형을 선택적 인수로 사용하여 (예외 유형을 매개 변수화 할 수 있습니까?), 모든 예외를 무시하는 대신 예기치 않은 예외가 위쪽으로 발생하도록 할 수 있습니다.
00prometheus 2011

3
@Bryan, "python 3에서는 'handle'인수 키워드 만 만들고 인수 목록의 끝에 넣습니다."에 대한 코드를 제공 할 수 있습니까? handle후에 배치 를 시도 **kwarg하고 SyntaxError. 역 참조를 의미 kwargs.get('handle',e)합니까?
alancalvitti

21

당신이 사용할 수있는

[1/egg for egg in eggs if egg != 0]

이것은 단순히 0 인 요소를 건너 뜁니다.


28
이것은 목록 이해에서 예외를 처리하는 방법에 대한 질문에 대답하지 않습니다.
Nathan Fellman

8
음, 그렇습니다. 예외를 처리 할 필요가 없습니다. 예, 항상 올바른 솔루션은 아니지만 일반적인 솔루션입니다.
Peter

3
이해 했어요. 나는 그 코멘트를 되 돌린다 (단, 그 짧은 '토론'이 대답을 향상시키기 때문에 나는 그것을 삭제하지 않을 것이다).
Nathan Fellman

11

더 좋은 방법은 없습니다. 많은 경우에 Peter처럼 회피를 사용할 수 있습니다.

다른 옵션은 이해력을 사용하지 않는 것입니다

eggs = (1,3,0,3,2)

result=[]
for egg in eggs:
    try:
        result.append(egg/0)
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

그것이 더 성가 신지 아닌지를 결정하는 것은 당신에게 달려 있습니다.


1
여기서 이해력을 어떻게 사용합니까?
Nathan Fellman

@Nathan : 당신은하지 않을 것입니다. gnibbler의 말 : 더 나은 방법은 없습니다
SilentGhost

죄송합니다 ... 나는 그의 대답에서 'not'을 놓쳤습니다. :-)
Nathan Fellman

4

나는 초기 질문을하는 사람과 브라이언 헤드가 제안한 도우미 기능이 좋고 전혀 번거롭지 않다고 생각한다. 모든 작업을 수행하는 한 줄의 매직 코드가 항상 가능한 것은 아니므로 for루프 를 피하려는 경우 도우미 함수가 완벽한 솔루션 입니다. 그러나 나는 이것을 이것으로 수정할 것입니다.

# A modified version of the helper function by the Question starter 
def spam(egg):
    try:
        return 1/egg, None
    except ZeroDivisionError as err:
        # handle division by zero error        
        return None, err

출력은 this [(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)]입니다. 이 답변을 사용하면 원하는 방식으로 계속 진행할 수 있습니다.


좋은. 이것은 Either일부 함수형 프로그래밍 언어 (예 : Scala) 의 유형 과 매우 유사합니다. 여기서 an Either은 한 유형 또는 다른 유형의 값을 포함 할 수 있지만 둘 다 포함 할 수는 없습니다. 유일한 차이점은 이러한 언어에서는 오류를 왼쪽에, 값을 오른쪽에 두는 것이 관용적이라는 것입니다. 자세한 정보는 다음과 같습니다 .
Alex Palmer

3

나는 이것을 언급하는 대답을 보지 못했습니다. 그러나이 예제는 알려진 실패 사례에 대해 예외가 발생하는 것을 방지하는 한 가지 방법입니다.

eggs = (1,3,0,3,2)
[1/egg if egg > 0 else None for egg in eggs]


Output: [1, 0, None, 0, 0]

이 답변과 같지 않습니까? stackoverflow.com/a/1528244/1084
Nathan Fellman

미묘한 차이가 있습니다. 필터링은 입력 목록이 아닌 출력에 적용됩니다. 게시 된 예에서 볼 수 있듯이 예외를 유발할 수있는 사례를 "없음"으로 표시했습니다.
Slakker
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.