Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

Можно ли считать, что нет последнего файла? Тогда обязательно, просто верните None.

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

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

Ответ 2

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

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

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

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

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

Надеюсь, это поможет!

Ответ 3

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

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

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

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

который, девять раз из десяти, является тем, что будет видеть вызывающий, если вы вернете необработанное Нет, не беспокойтесь.

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

Ответ 4

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

Ответ 5

с набором символов python 3.5:

пример функции при возврате None будет:

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

и при создании исключения будет:

def latestpdf(folder: str) -> str 

вариант 2 кажется более читаемым и питоническим

(+option, чтобы добавить комментарий к исключению, как указано ранее).