예외 발생 대 함수에서 None 반환?


85

파이썬의 사용자 정의 함수에서 더 나은 방법 : raise예외 또는 return None? 예를 들어 폴더에서 가장 최근 파일을 찾는 기능이 있습니다.

def latestpdf(folder):
    # list the files and sort them
    try:
        latest = files[-1]
    except IndexError:
        # Folder is empty.
        return None  # One possibility
        raise FileNotFoundError()  # Alternative
    else:
        return somefunc(latest)  # In my case, somefunc parses the filename

또 다른 옵션은 예외를 남겨두고 호출자 코드에서 처리하는 FileNotFoundError것입니다 IndexError.하지만. 아니면 다른 이름으로 예외를 다시 제기하는 것이 나쁜 형식입니까?



3
예외를 발생시키는쪽으로 기울여서 호출 함수에서 예외를 처리해야합니다. 호출 함수에서 출력이 None인지 확인하는 것을 잊으면 잠재적 인 버그가있을 수 있습니다. None을 반환했다면 호출 함수의 다음 줄에서 AttributeError가 발생하기를 바랍니다. 그러나 반환 된 값이 사전에 추가 된 다음 다른 소스 파일에서 100 개의 함수 호출이 발생하면 AttributeError가 발생하면 해당 값이 None 인 이유를 쉽게 찾을 수 있습니다.
IceArdor

일반적으로 특별한 의미가 있거나 하나의 함수에 대해 여러 서명이있는 값도 피합니다 (문자열 또는 없음을 반환 할 수 있음).
IceArdor

답변:


91

그것은 정말로 의미론의 문제입니다. 무슨 foo = latestpdf(d) 이야?

최신 파일이 없다는 것이 완벽하게 합리적입니까? 그런 다음 None을 반환하십시오.

항상 최신 파일을 찾길 원하십니까? 예외를 발생시킵니다. 그리고 예, 더 적절한 예외를 다시 제기하는 것은 괜찮습니다.

이것이 모든 디렉토리에 적용되어야하는 일반적인 함수라면 전자를 수행하고 None을 반환합니다. 예를 들어 디렉터리가 응용 프로그램의 알려진 파일 집합을 포함하는 특정 데이터 디렉터리를 의미하는 경우 예외를 발생시킵니다.


3
고려해야 할 또 다른 사항 : 예외를 발생 시키면 메시지를 첨부 할 수 있지만을 반환 할 때는 그렇게 할 수 없습니다 None.
kawing-chiu

9

질문에 대한 답변이 될 수 있으므로 질문에 답변하기 전에 몇 가지 제안을하겠습니다.

  • 항상 설명적인 이름을 지정하십시오. latestpdf누구에게도 거의 의미가 없지만 기능을 살펴보면 latestpdf()최신 pdf를 얻을 수 있습니다 . 이름을 지정하는 것이 좋습니다 getLatestPdfFromFolder(folder).

이 작업을 수행하자마자 무엇을 반환해야하는지 명확 해졌습니다. pdf가 없으면 예외를 발생시킵니다. 하지만 더 기다려 ..

  • 기능을 명확하게 정의하십시오. somefuc이 무엇을해야하는지 명확하지 않고 최신 pdf를 얻는 것과 관련이있는 것이 (분명히) 분명하지 않기 때문에 나는 당신이 그것을 밖으로 옮기는 것이 좋습니다. 이것은 코드를 훨씬 더 읽기 쉽게 만듭니다.

for folder in folders:
   try:
       latest = getLatestPdfFromFolder(folder)
       results = somefuc(latest)
   except IOError: pass

도움이 되었기를 바랍니다!


또는 get_latest_pdf_from_folder. 사실, Pep8 : "함수 이름은 소문자 여야하며, 가독성을 높이기 위해 필요에 따라 단어를 밑줄로 구분해야합니다."
PatrickT

7

파이썬은 동적으로 입력되기 때문에 일반적으로 내부적으로 예외를 처리하는 것을 선호합니다 (즉, 호출 된 함수 내부에서 try / except, 가능하면 None 반환). 일반적으로 나는 그것이 어떤 식 으로든 판단 호출이라고 생각하지만, 동적으로 입력되는 언어에서는 예외를 호출자에게 전달하지 않기 위해 스케일을 기울이는 작은 요소가 있습니다.

  1. 함수를 호출하는 사람에게는 throw 될 수있는 예외에 대한 알림이 표시되지 않습니다. 어떤 종류의 예외를 찾고 있는지 아는 것은 약간의 예술 형식이됩니다 (블록 제외는 피해야합니다).
  2. if val is None보다 조금 쉽습니다 except ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace. 진지하게, 나는 from django.core.exceptions import ObjectDoesNotExist정말로 일반적인 사용 사례를 처리하기 위해 모든 django 파일의 상단에 입력하는 것을 기억해야하는 것을 싫어 합니다. 정적으로 입력 된 세계에서 편집자가 대신 수행하도록하십시오.

하지만 솔직히 이것은 항상 판단 호출이며 호출 된 함수가 도울 수없는 오류를 수신하는 상황을 설명하는 것은 의미있는 예외를 다시 발생시키는 훌륭한 이유입니다. 정확한 아이디어가 있지만 예외가 아니라면 스택 추적에서 더 의미있는 정보를 제공 할 것입니다.

AttributeError: 'NoneType' object has no attribute 'foo'

10 점 만점에 9 번, 처리되지 않은 None을 반환하면 호출자가 보게 될 것입니다. 귀찮게하지 마십시오.

(이 모든 종류의 cause자바에서와 같이 기본적으로 파이썬 예외에 속성 이 있기를 바라며 ,이를 통해 예외를 새로운 예외로 전달할 수 있으므로 원하는 모든 것을 다시 던져 문제의 원래 소스를 잃지 않을 수 있습니다.)


가능한 예외가 정의되지 않았기 때문에 포착하기 어렵다는 주장은 파이썬에 매우 유효한 주장입니다.
snorberhuis

4

파이썬 3.5의 타이핑으로 :

None을 반환 할 때 예제 함수는 다음과 같습니다.

def latestpdf(folder: str) -> Union[str, None]

예외를 발생시킬 때 :

def latestpdf(folder: str) -> str 

옵션 2는 더 읽기 쉽고 비단뱀처럼 보입니다.

(앞서 언급 한대로 예외에 주석을 추가하는 + 옵션.)


4
Union[str, None]이어야합니다Optional[str]
Georgy

2
속기이지만 당신 말이 맞습니다. 더 읽기 쉽습니다. 두 가지 옵션이 모두 여기에 있습니다.
Asaf

2는 잠재적으로 더 읽기 쉽지만 (불행히도?) 유형 힌트는 예외가 발생할 수 있음을 나타내지 않습니다. 최근에 None 반환을 처리해야하므로 1이 더 많은 오류를 포착하는 데 도움이된다는 것을 발견했습니다.
jonespm

2

일반적으로 복구 할 수없는 치명적인 문제가 발생하면 예외가 발생해야하며 (즉, 함수가 연결할 수없는 인터넷 리소스를 처리하는 경우) 함수가 실제로 무언가를 반환해야하는 경우 None을 반환해야합니다. 그러나 반환하기에 적절한 것은 없습니다 (예를 들어 함수가 문자열의 하위 문자열과 일치하려고하면 "None").

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