Обработка исключений игнорируется в try-кроме определения функции - PullRequest
1 голос
/ 11 октября 2019

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

#!/usr/bin/python

t = raw_input("do you want to play a game?[y/n]" )

#r = raw_input("Please enter a number")

#e = raw_input("Please enter a number again")

try:
 def di (a, b):
  return  a/b
except ZeroDivisionError:
 print "Divide by 0 Error"

while t == "y":
  u = raw_input("Please enter / sign ")
  if u == "/":
   r = int(raw_input("Please enter a number"))
  try:
   e = int(raw_input("Please enter a number again"))
   print "the answer is", di(r, e)
   t = raw_input("do you want to play a game?[y/n]" )


  except ValueError:
   t = raw_input( "Invalid input, must be a number. Press yes to continue, no stop")

Ответы [ 3 ]

2 голосов
/ 11 октября 2019

Посмотрите на код более внимательно:

try:
    def di (a, b):
        return  a/b

except ZeroDivisionError:
    print "Divide by 0 Error"

Ваш блок try/except включает в себя полное определение функции: он применяется конкретно к , определяющему функцию. Пока функция выполняется из вызова, активный блок исключений не активен.

Используйте вместо этого:

def di (a, b):
    try:
        return  a/b
    except ZeroDivisionError:
        print "Divide by 0 Error"
0 голосов
/ 11 октября 2019

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

try:
    def di (a, b):
        return  a/b
except ZeroDivisionError:
    print "Divide by 0 Error"

говорит:

"Попытка определить функцию с именем di, которая возвращает дивиденды своих аргументов. Если определение функции вызывает исключение ZeroDivisionError, выведите пояснительное сообщение«. Никаких исключений не будет.

Я подозреваю, что вместо этого требуется:

"Определить функцию, которая пытается вернуть дивиденды своих аргументов. Если при делении возникает исключение ZeriDivisionError,Функция печатает пояснительное сообщение и возвращает None. "Таким образом, def должен соответствовать логике всей функции:

def di(a, b):
    try:
        return a/b
    except ZeroDivisionError:
        print "Divide by 0 error"

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

Указание на недействительность данных, возвращая объект другого типа, создает сложный и трудно читаемый код, и, вероятно, его лучше избегать в долгосрочной перспективе. Вполне приемлемо для учебного упражнения, хотя!

0 голосов
/ 11 октября 2019

TLDR: переместите обработчик исключения в функцию, где на самом деле происходит исключение:

def di(a, b):
    try:
        return a/b
    except ZeroDivisionError:
        print("Divide by 0 Error")

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

>>> def func(arg=print("default evaluated")):
...     print("body evaluated")
...
default evaluated
>>> func
<function __main__.func(arg=None)>
>>> func()
body evaluated

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

>>> def invalid_def(arg=10/0):
...     pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

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

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

>>> def invalid_call():
...     return 10 / 0
...
>>> invalid_call()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero
>>> invalid_call()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero

Существует два способа обработки таких исключений: внешне или внутренне.

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

    >>> try:
    ...     invalid_call()
    ... except ZeroDivisionError:
    ...     print("suppressed an external error")
    
  • Внутренняя обработка требует обработчика исключений в теле. Это менее гибко, но не нуждается в шаблоне, поскольку один обработчик исключений охватывает все случаи.

    >>> def valid_call():
    ...     try:
    ...         return 10 / 0
    ...     except ZeroDivisionError:
    ...         print("suppressed an internal error")
    

Оба подхода верны;что выбрать, зависит от того, нужно ли вам удобство использования или повторного использования. Примечательно, что нередки случаи объединения обоих подходов: внутренний обработчик обобщает исключение, а внешний обработчик ожидает только общие исключения.

Например, в вашем случае это позволит обрабатывать несколько операций:

def div(a, b):
    try:
        return  a / b
    # convert operation-specific exception to general one
    except ZeroDivisionError:
        raise ValueError("Cannot divide by 0")

# may be another operation -- add, mul, sub, ...
operation = div

try:
    operation(10, 0)
# only handle exception general to all operations
except ValueError as err:
    print("Invalid values: %s" % err)
...