Проверка условия по сравнению с Обработкой исключений [дубликат]

16
задан Luc Touraille 3 November 2011 в 15:38
поделиться

6 ответов

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

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

9
ответ дан 30 November 2019 в 22:02
поделиться

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

Итак, если вы думаете о своей функции «добавить». Он НИКОГДА не должен возвращать null. Это не согласованный результат для добавления двух вещей. В этом случае в переданных аргументах есть ошибка, и функция должна не пытаться делать вид, что все в порядке. Это идеальный случай для исключения исключения.

Вы можете использовать проверку условий и возвращать null, если вы находитесь в обычном или нормальном случае выполнения. Например, IsEqual может быть хорошим случаем для использования условий и возврата false, если одно из ваших условий не выполняется. I.E.

function bool IsEqual(obj a, obj b)
{ 
   if(a is null) return false;
   if(b is null) return false;
   if(a.Type != b.Type) return false;

   bool result = false;
   //Do custom IsEqual comparison code
   return result;
}

В этом сценарии вы возвращаете false как для исключительных случаев, так и для случая «объекты не равны». Это означает, что потребитель (вызывающая сторона) не может сказать, было ли сравнение неудачным или объекты просто не равны . Если эти случаи необходимо различать, вам следует использовать исключения вместо условий.

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

6
ответ дан 30 November 2019 в 22:02
поделиться

Отсутствие GeneratedCode можно обойти. , используя вашу собственную ветвь частичных классов для применения этого атрибута. Это будет означать, что любой добавленный вами пользовательский код (включая реализацию частичных методов) будет исключен. Например: [

namespace MyApp.DB {
    [GeneratedCode("LINQ To SQL", "4.0")]
    internal partial class MyAppDataContext {
    }

    // Repeat for each entity
}
-121--4903877-

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

Во второй реализации sum_ пользователь должен каждый раз проверять значение . Это напоминает шаблон C / Fortran / других языков (и частый источник ошибок), где коды ошибок не проверяются, чего мы избегаем. Вы должны писать такой код на всех уровнях, чтобы иметь возможность распространять ошибки. Это становится беспорядочным, и его особенно избегают в Python.

Еще пара примечаний:

  • Часто вам не нужно делать собственные исключения.Для многих случаев подходят встроенные исключения, такие как ValueError и TypeError .
  • Когда я создаю новое исключение, что очень полезно, я часто пытаюсь создать подкласс чего-то более конкретного, чем Exception . Встроенная иерархия исключений здесь .
  • Я бы никогда не реализовал такую ​​функцию, как sum_ , поскольку проверка типов делает ваш код менее гибким, поддерживаемым и идиоматическим.

    Я бы просто написал функцию

     def sum_ (a, b): 
    return a + b 
     

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

     >>> sum_ (1, 4) 
    5 
     >>> sum_ (4.5, 5.0) 
    9.5 
     >> > sum _ ([1, 2], [3, 4]) 
     [1, 2, 3, 4] 
     >>> sum_ (3.5, 5) # Эта операция имеет смысл, но у вас ничего не получится 
    8.5 
     >>> sum _ ("cat", 7) # Это не имеет смысла и уже является ошибкой. 
    Traceback (последний вызов последним) : 
    Файл "", строка 1, в  
    Файл "", строка 1, в сумме _ 
    TypeError: невозможно объединить 'str' и Объекты int 
     

    Мой код был короче и проще, но при этом более надежен и гибок, чем ваш. Вот почему мы избегаем проверки типов в Python.

2
ответ дан 30 November 2019 в 22:02
поделиться

Вы должны генерировать исключение, если параметр содержит неожиданное значение.

В ваших примерах я бы рекомендовал генерировать исключение, когда два параметра имеют разные типы.

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

1
ответ дан 30 November 2019 в 22:02
поделиться

Может быть sum_ в одиночку выглядит нормально. Что, если, вы знаете, он действительно используется?

#foo.py
def sum_(a, b):
    if type(a) == type(b):
        return a + b

#egg.py
from foo import sum_:
def egg(c = 5):
  return sum_(3, c)

#bar.py
from egg import egg
def bar():
  return len(egg("2"))
if __name__ == "__main__":
  print bar()

Если вы запустите bar.py , вы получите:

Traceback (most recent call last):
  File "bar.py", line 6, in <module>
    print bar()
  File "bar.py", line 4, in bar
    return len(egg("2"))
TypeError: object of type 'NoneType' has no len()

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

Тот, кто хочет исправить эту ошибку, должен сначала дважды проверить bar.py , а затем проанализировать egg.py , пытаясь выяснить, откуда именно появился None. После чтения egg.py им нужно будет прочитать sum_.py и, надеюсь, заметить неявный возврат None ; только тогда они понимают проблему: они не прошли проверку типа из-за введенного для них параметра egg.py .

Добавьте сюда немного реальной сложности, и все очень быстро станет уродливым.

Python, в отличие от C, написан с учетом принципа Проще просить прощения, чем разрешения : если что-то пойдет не так, я получу исключение . Если вы передадите мне None , где я ожидаю фактического значения, все сломается, исключение произойдет далеко от линии, которая его действительно вызывает, и люди будут проклинать в вашем общем направлении в двадцать различных языков, затем измените код, чтобы создать подходящее исключение ( TypeError («несовместимый тип операнда») ).

0
ответ дан 30 November 2019 в 22:02
поделиться

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

Есть и другие причины, которые я объяснил здесь: Исключения против возвратов состояния .

2
ответ дан 30 November 2019 в 22:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: