Поиск…


Переусердствовать, кроме оговорки

Исключения являются мощными, но одна чрезмерно усредненная фраза может занять все это в одной строке.

try:
    res = get_result()
    res = res[0]
    log('got result: %r' % res)
except:
    if not res:
        res = ''
    print('got exception')

Этот пример демонстрирует 3 симптома антипаттера:

  1. За except без указания типа исключения (строка 5) будет ловить даже здоровые исключения, в том числе KeyboardInterrupt . Это предотвратит выход из программы в некоторых случаях.
  2. Блок except не регрессирует ошибку, что означает, что мы не сможем определить, произошло ли исключение из get_result или потому, что res был пустым.
  3. Хуже всего, если бы мы были обеспокоены тем, что результат был пуст, мы привели к чему-то значительно худшему. Если get_result не удался, res останется полностью отключенным, а ссылка на res в NameError блоке повысит значение NameError , полностью маскируя исходную ошибку.

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

Вот фиксированная версия приведенного выше примера:

import traceback

try:
    res = get_result()
except Exception: 
    log_exception(traceback.format_exc())
    raise
try:
    res = res[0]
except IndexError:
    res = ''

log('got result: %r' % res)

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

Глядя перед вами, прыгайте с интенсивной работой процессора

Программа может легко тратить время, вызывая многократно процессорную функцию.

Например, возьмите функцию, которая выглядит так: она возвращает целое число, если входное value может создать одно, иначе None :

def intensive_f(value): # int -> Optional[int]
   # complex, and time-consuming code
   if process_has_failed:
       return None
   return integer_output

И его можно использовать следующим образом:

x = 5
if intensive_f(x) is not None:
    print(intensive_f(x) / 2)
else:
    print(x, "could not be processed")

print(x)

Пока это будет работать, возникает проблема вызова intensive_f , что удваивает время выполнения кода. Лучшим решением было бы получить возвращаемое значение функции заранее.

x = 5
result = intensive_f(x)
if result is not None:
    print(result / 2)
else:
    print(x, "could not be processed")

Однако более ясный и, возможно, более питонический способ заключается в использовании исключений, например:

x = 5
try:
    print(intensive_f(x) / 2)
except TypeError: # The exception raised if None + 1 is attempted
    print(x, "could not be processed")

Здесь не требуется временная переменная. Часто может быть предпочтительнее использовать оператор assert и вместо этого ухватить AssertionError .

Словарь ключей

Общим примером того, где это можно найти, является доступ к клавишам словаря. Например, сравните:

bird_speeds = get_very_long_dictionary()

if "european swallow" in bird_speeds:
    speed = bird_speeds["european swallow"]
else:
    speed = input("What is the air-speed velocity of an unladen swallow?")

print(speed)

с:

bird_speeds = get_very_long_dictionary()

try:
    speed = bird_speeds["european swallow"]
except KeyError:
    speed = input("What is the air-speed velocity of an unladen swallow?")

print(speed)

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

Альтернативой этому является использование dict.get(key, default) , однако многим обстоятельствам может потребоваться выполнение более сложных операций в случае, если ключ отсутствует



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow