Поднять исключение против возврата нет в функциях?


что лучше практиковать в пользовательской функции в Python: 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. Или это плохой тон, чтобы повторно поднять исключение с другим именем?

4 62

4 ответа:

Это действительно вопрос семантики. Что значит foo = latestpdf(d)значит?

вполне ли разумно, что нет последнего файла? Тогда конечно, просто нет.

вы ожидаете, что всегда найдете последний файл? Вызвать исключение. И да, повторное поднятие более подходящего исключения прекрасно.

Если это просто общая функция, которая должна применяться к любому каталогу, я бы сделал первое и не вернул ни одного. Если каталог, например, означает чтобы быть определенным каталогом данных, который содержит известный набор файлов приложения, я бы вызвал исключение.

Я хотел бы сделать несколько предложений, прежде чем ответить на ваш вопрос, как он может ответить на вопрос.

  • всегда называйте свои функции описательными. latestpdf означает очень мало для кого, но глядя на вашу функцию latestpdf() получает последний pdf. Я бы предложил вам назвать его getLatestPdfFromFolder(folder).

как только я это сделал стало ясно, что он должен вернуться.. Если нет pdf-файла, возникает исключение. Но подождите там больше..

  • сохранить функции четко определены. Поскольку не очевидно, что somefuc должен делать, и это (по-видимому) не очевидно, как это связано с получением последнего pdf, я бы предложил вам переместить его. Это делает код гораздо более читаемым.

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

надеюсь, что это помогает!

Я обычно предпочитаю обрабатывать исключения внутри (т. е. try/except внутри вызываемой функции, возможно, возвращая None), потому что python динамически типизирован. В общем, я считаю это вызовом суждения так или иначе, но в динамически типизированном языке есть небольшие факторы, которые склоняют чашу весов в пользу того, чтобы не передавать исключение вызывающему:

  1. любой вызывающий вашу функцию не уведомляется об исключениях, которые могут быть брошены. Это становится немного форма искусства, чтобы знать, какое исключение вы ищете (и общие, кроме блоков следует избегать).
  2. if val is None немного легче, чем except ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace. Серьезно, я ненавижу вспоминать, чтобы напечатать from django.core.exceptions import ObjectDoesNotExist в верхней части всех моих файлов django просто для обработки действительно распространенного случая использования. В статически типизированном мире, пусть редактор сделает это за вас.

честно говоря, это всегда вызов суждения, и ситуация, которую вы описываете, где вызываемая функция получает ошибку, которая не может помочь, является отличной причиной для повторного создания исключения, которое имеет смысл. У вас есть точная правильная идея, но если вы не исключение, вы будете предоставлять более значимую информацию в трассировке стека, чем

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

который, в девяти случаях из десяти, это то, что абонент увидит, если вы вернете необработанный None, не беспокойтесь.

(все это заставляет меня желать, чтобы исключения python имели cause атрибуты по умолчанию, как и в java, что позволяет вы передаете исключения в новые исключения, чтобы вы могли перестроить все, что хотите, и никогда не потерять исходный источник проблемы.)

В общем, я бы сказал, что исключение должно быть выброшено, если произошло что-то катастрофическое, что не может быть восстановлено (т. е. ваша функция имеет дело с каким-то интернет-ресурсом, к которому нельзя подключиться), и вы должны вернуть None, если ваша функция действительно должна что-то вернуть, но ничего не будет подходящим для возврата (т. е. "нет", если ваша функция пытается соответствовать подстроке в строке, например).