Как это помогает разделить исключение на подклассы? - PullRequest
1 голос
/ 27 февраля 2020

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

class ACustomException(Exception):
    pass

class BCustomException(Exception):
    pass

Ответы [ 3 ]

3 голосов
/ 27 февраля 2020

Повышение Exception - это все равно, что сказать доктору "Что-то не так", а затем отказаться отвечать на любые вопросы. Сравните:

try:
    with open("foo.json", "rt") as r:
        new_count = json.load(r)["count"] + 1
except Exception:
    # Is the file missing?
    # Is the file there, but not readable?
    # Is the file readable, but does not contain valid JSON?
    # Is the file format okay, but the data's not a dict with `count`?
    # Is the entry `count` there, but is not a number?
    print("Something's wrong")
    # I don't care. You figure it out.

и

try:
    with open("data.json", "rt") as r:
        new_count = json.load(r)["count"] + 1
except FileNotFoundError:
    print("File is missing.")
except PermissionError:
    print("File not readable.")
except json.decoder.JSONDecoderError:
    print("File is not valid JSON.")
except KeyError:
    print("Cannot find count.")
except TypeError:
    print("Count is not a number.")

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

Например, Django определит исключение django.contrib.auth.models.User.DoesNotExist, чтобы сообщить, что код пытался найти User в базе данных, но не User соответствие заданным критериям может быть найдено. Возможность поймать django.contrib.auth.models.User.DoesNotExist - это все равно, что быть врачом, и получить пациента, который не только говорит вам, что болит, но и приносит с собой рентген и напечатанную семейную историю.

2 голосов
/ 27 февраля 2020

Когда вы обрабатываете исключения с помощью try-exc, вы перехватываете их по имени , поэтому наличие имен c поможет вам обработать их.

Например, если функция вызывает Exception для любой ошибки, логика перехвата c усложняется:

def foobar():
    if FOO:
        raise Exception('FOO happened')
    elif BAR:
        raise Exception('BAR happened')

try:
    foobar()
except Exception as e:
    if e.args == ('FOO happened',):
        print('Handling FOO')
    elif e.args == ('BAR happened',):
        print('Handling BAR')
    else:
        raise

С другой стороны, если у вас есть подклассифицированные исключения, логика перехвата c проста:

class FooError(Exception):
    pass

class BarError(Exception):
    pass

def function():
    if FOO:
        raise FooError('FOO happened')
    elif BAR:
        raise BarError('BAR happened')

try:
    function()
except FooError:
    print('Handling FOO')
except BarError:
    print('Handling BAR')
0 голосов
/ 27 февраля 2020

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

Чтобы быть более точным c с примером:

val = int(input('Enter a number:'))
try:
  val *= val
except ValueError as e:
  raise e
print(val)

### ValueError will be raised if user inputs something other than a number
### this raise e will return the actual error message saying 
### ValueError: invalid literal for int() with base 10: 'ok'

В вашем случае вы все равно можете повысить свое исключение, сохранив ValueError в качестве исключения, которое будет обработано ибо вот так:

val = int(input('Enter a number:'))
try:
  val *= val
except ValueError as e:
  raise ACustomException('some debug statement referring to the cause of the error')

print(val)

### now this will raise your exception class besides the ValueError exception, with a debug statement if you choose to have one in it.
...