"Правильний спосіб оголосити спеціальні винятки в сучасному Python?"
Це добре, якщо виняток не є типом більш конкретного винятку:
class MyException(Exception):
pass
Або краще (можливо, ідеально), замість того, щоб pass
надати доктрину:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Підкласи винятків підкласів
Від док
Exception
Усі вбудовані винятки, що не входять в систему, походять з цього класу. Усі винятки, визначені користувачем, також повинні походити з цього класу.
Це означає, що якщо ваш виняток є типом більш конкретного винятку, підклас цього винятку замість загального Exception
(і результат буде таким, який ви все ще отримуєте з Exception
рекомендацій, які рекомендують документи). Крім того, ви можете принаймні надати docstring (і не бути змушеним використовувати pass
ключове слово):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Встановлюйте атрибути, які ви створюєте самостійно за допомогою спеціального користування __init__
. Уникайте передачі дикту як позиційного аргументу, майбутні користувачі вашого коду будуть вам вдячні. Якщо ви використовуєте атрибут застарілого повідомлення, призначаючи його самостійно, ви уникнете DeprecationWarning
:
class MyAppValueError(ValueError):
'''Raise when a specific subset of values in context of app is wrong'''
def __init__(self, message, foo, *args):
self.message = message # without this you may get DeprecationWarning
# Special attribute you desire with your Error,
# perhaps the value that caused the error?:
self.foo = foo
# allow users initialize misc. arguments as any other builtin Error
super(MyAppValueError, self).__init__(message, foo, *args)
Насправді не потрібно писати свій власний __str__
або __repr__
. Вбудовані дуже приємні, і ваше спільне спадщину гарантує, що ви ним користуєтесь.
Критика верхньої відповіді
Можливо, я пропустив питання, але чому б ні:
class MyException(Exception):
pass
Знову ж таки, проблема вищезазначеного полягає в тому, що для того, щоб зловити його, вам доведеться або назвати його конкретно (імпортувати його, якщо створено в іншому місці), або вилучити виняток (але ви, мабуть, не готові обробляти всі типи винятків, і ви повинні виловлювати лише винятки, з якими ви готові впоратися). Аналогічна критика нижче, але крім того, це не спосіб ініціалізації через super
, і ви отримаєте, DeprecationWarning
якщо ви отримаєте доступ до атрибуту повідомлення:
Редагувати: щоб щось замінити (або пропустити додаткові аргументи), зробіть це:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super(ValidationError, self).__init__(message)
# Now for your custom code...
self.errors = errors
Таким чином, ви можете передати дік повідомлень про помилки до другого параметра та дістатись до нього пізніше за допомогою ererrors
Він також вимагає передавати рівно два аргументи (окрім self
.) Не більше, не менше. Це цікаве обмеження, яке майбутні користувачі можуть не оцінити.
Бути прямим - це порушує замість Ліскова .
Я продемонструю обидві помилки:
>>> ValidationError('foo', 'bar', 'baz').message
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
ValidationError('foo', 'bar', 'baz').message
TypeError: __init__() takes exactly 3 arguments (4 given)
>>> ValidationError('foo', 'bar').message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foo'
У порівнянні з:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'