Кастомные ошибки python

«What is the proper way to declare custom exceptions in modern Python?»

This is fine unless your exception is really a type of a more specific exception:

class MyException(Exception):
    pass

Or better (maybe perfect), instead of pass give a docstring:

class MyException(Exception):
    """Raise for my specific kind of exception"""

Subclassing Exception Subclasses

From the docs

Exception

All built-in, non-system-exiting exceptions are derived from this class.
All user-defined exceptions should also be derived from this
class.

That means that if your exception is a type of a more specific exception, subclass that exception instead of the generic Exception (and the result will be that you still derive from Exception as the docs recommend). Also, you can at least provide a docstring (and not be forced to use the pass keyword):

class MyAppValueError(ValueError):
    '''Raise when my specific value is wrong'''

Set attributes you create yourself with a custom __init__. Avoid passing a dict as a positional argument, future users of your code will thank you. If you use the deprecated message attribute, assigning it yourself will avoid a 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) 

There’s really no need to write your own __str__ or __repr__. The built-in ones are very nice, and your cooperative inheritance ensures that you use them.

Critique of the top answer

Maybe I missed the question, but why not:

class MyException(Exception):
    pass

Again, the problem with the above is that in order to catch it, you’ll either have to name it specifically (importing it if created elsewhere) or catch Exception, (but you’re probably not prepared to handle all types of Exceptions, and you should only catch exceptions you are prepared to handle). Similar criticism to the below, but additionally that’s not the way to initialize via super, and you’ll get a DeprecationWarning if you access the message attribute:

Edit: to override something (or pass extra args), do this:

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

That way you could pass dict of error messages to the second param, and get to it later with e.errors

It also requires exactly two arguments to be passed in (aside from the self.) No more, no less. That’s an interesting constraint that future users may not appreciate.

To be direct — it violates Liskov substitutability.

I’ll demonstrate both errors:

>>> 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'

Compared to:

>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'

Summary: in this tutorial, you’ll learn how to define Python custom exception classes.

Introduction to the Python custom exception

To create a custom exception class, you define a class that inherits from the built-in Exception class or one of its subclasses such as ValueError class:

Python Custom Exception

The following example defines a CustomException class that inherits from the Exception class:

class CustomException(Exception):
    """ my custom exception class """Code language: Python (python)

Note that the CustomException class has a docstring that behaves like a statement. Therefore, you don’t need to add the pass statement to make the syntax valid.

To raise the CustomException, you use the raise statement. For example, the following uses the raise statement to raise the CustomException:

class CustomException(Exception):
    """ my custom exception class """


try:
    raise CustomException('This is my custom exception')
except CustomException as ex:
    print(ex)Code language: Python (python)

Output:

This is my custom exceptionCode language: Python (python)

Like standard exception classes, custom exceptions are also classes. Hence, you can add functionality to the custom exception classes like:

  • Adding attributes and properties.
  • Adding methods e.g., log the exception, format the output, etc.
  • Overriding the __str__ and __repr__ methods
  • And doing anything else that you can do with regular classes.

In practice, you’ll want to keep the custom exceptions organized by creating a custom exception hierarchy. The custom exception hierarchy allows you to catch exceptions at multiple levels, like the standard exception classes.

Suppose you need to develop a program that converts a temperature from Fahrenheit to Celsius.

The minimum and maximum values of a temperature in Fahrenheit are 32 and 212. If users enter a value that is not in this range, you want to raise a custom exception e.g., FahrenheitError.

Define the FahrenheitError custom exception class

The following defines the FahrenheitError exception class:

class FahrenheitError(Exception):
    min_f = 32
    max_f = 212

    def __init__(self, f, *args):
        super().__init__(args)
        self.f = f

    def __str__(self):
        return f'The {self.f} is not in a valid range {self.min_f, self.max_f}'Code language: Python (python)

How it works.

  • First, define the FahrenheitError class that inherits from the Exception class.
  • Second, add two class attributes min_f and max_f that represent the minimum and maximum Fahrenheit values.
  • Third, define the __init__ method that accepts a Fahrenheit value (f) and a number of position arguments (*args). In the __init__ method, call the __init__ method of the base class. Also, assign the f argument to the f instance attribute.
  • Finally, override the __str__ method to return a custom string representation of the class instance.

Define the fahrenheit_to_celsius function

The following defines the fahrenheit_to_celsius function that accepts a temperature in Fahrenheit and returns a temperature in Celcius:

def fahrenheit_to_celsius(f: float) -> float:
    if f < FahrenheitError.min_f or f > FahrenheitError.max_f:
        raise FahrenheitError(f)

    return (f - 32) * 5 / 9Code language: Python (python)

The fahrenheit_to_celsius function raises the FahrenheitError excpetion if the input temperature is not in the valid range. Otherwise, it converts the temperature from Fahrenheit to Celcius.

Create the main program

The following main program uses the fahrenheit_to_celsius function and the FahrenheitError custom exception class:

if __name__ == '__main__':
    f = input('Enter a temperature in Fahrenheit:')
    try:
        f = float(f)
    except ValueError as ex:
        print(ex)
    else:
        try:
            c = fahrenheit_to_celsius(float(f))
        except FahrenheitError as ex:
            print(ex)
        else:
            print(f'{f} Fahrenheit = {c:.4f} Celsius')Code language: Python (python)

How it works.

First, prompt users for a temperature in Fahrenheit.

f = input('Enter a temperature in Fahrenheit:')Code language: Python (python)

Second, convert the input value into a float. If the float() cannot convert the input value, the program will raise a ValueError exception. In this case, it displays the error message from the ValueError exception:

try:
    f = float(f)
    # ...
except ValueError as ex:
    print(ex)Code language: Python (python)

Third, convert the temperature to Celsius by calling the fahrenheit_to_celsius function and print the error message if the input value is not a valid Fahrenheit value:

try:
    c = fahrenheit_to_celsius(float(f))
except FahrenheitError as ex:
    print(ex)
else:
    print(f'{f} Fahrenheit = {c:.4f} Celsius')Code language: Python (python)

Put it all together

class FahrenheitError(Exception):
    min_f = 32
    max_f = 212

    def __init__(self, f, *args):
        super().__init__(args)
        self.f = f

    def __str__(self):
        return f'The {self.f} is not in a valid range {self.min_f, self.max_f}'


def fahrenheit_to_celsius(f: float) -> float:
    if f < FahrenheitError.min_f or f > FahrenheitError.max_f:
        raise FahrenheitError(f)

    return (f - 32) * 5 / 9


if __name__ == '__main__':
    f = input('Enter a temperature in Fahrenheit:')
    try:
        f = float(f)
    except ValueError as ex:
        print(ex)
    else:
        try:
            c = fahrenheit_to_celsius(float(f))
        except FahrenheitError as ex:
            print(ex)
        else:
            print(f'{f} Fahrenheit = {c:.4f} Celsius')Code language: Python (python)

Summary

  • Subclass the Exception class or one of its subclasses to define a custom exception class.
  • Create a exception class hierarchy to make the exception classes more organized and catch exceptions at multiple levels.

Did you find this tutorial helpful ?

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

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

В примере создается определяемое пользователем исключение CustomError(), которое наследуется от класса Exception. Это новое исключение, как и другие исключения, может быть вызвано с помощью оператора raise с дополнительным сообщением об ошибке.

# Определяем собственное исключение
>>> class CustomError(Exception):
...     pass
...
>>> raise CustomError
# Traceback (most recent call last):
# ...
# __main__.CustomError

# Вызываем собственное исключение 
# 'CustomError' с сообщением об ошибке
>>> raise CustomError("An error occurred")
# Traceback (most recent call last):
# ...
# __main__.CustomError: An error occurred

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

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

Большинство пользовательских исключений определяются именами, которые заканчиваются на «Error», аналогично именованию стандартных исключений.

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

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

# определение пользовательских исключений
class Error(Exception):
    """Базовый класс для других исключений"""
    pass

class ValueTooSmallError(Error):
    """Вызывается, когда входное значение мало"""
    pass

class ValueTooLargeError(Error):
    """Вызывается, когда входное значение велико"""
    pass

# число, которое нужно угадать
number = 10

# игра продолжается до тех пор, 
# пока пользователь его не угадает
while True:
    try:
        i_num = int(input("Ввести число: "))
        if i_num < number:
            raise ValueTooSmallError
        elif i_num > number:
            raise ValueTooLargeError
        break
    except ValueTooSmallError:
        print("Это число меньше загаданного, попробуйте еще раз!n")
    except ValueTooLargeError:
        print("Это число больше загаданного, попробуйте еще раз!n")

print("Поздравляю! Вы правильно угадали.")

В примере определен базовый класс под названием Error(). Два других исключения, которые фактически вызываются программой (ValueTooSmallError и ValueTooLargeError), являются производными от класса Error().

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

Пример запуска скрипта с примером:

Ввести число: 12
Это число больше загаданного, попробуйте еще раз!

Ввести число: 0
Это число меньше загаданного, попробуйте еще раз!

Ввести число: 8
Это число меньше загаданного, попробуйте еще раз!

Ввести число: 10
Поздравляю! Вы правильно угадали.

Смотрим еще один простенький пример.

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

class Error(Exception):
    """Базовый класс для исключений в этом модуле."""
    pass

class InputError(Error):
    """Исключение для ошибок во входных данных.
    Attributes:
        expression -- выражение, в котором произошла ошибка
        message -- объяснение ошибки
    """
    def __init__(self, expression, message):
        self.expression = expression
        self.message = message


x = input("Ведите положительное целое число: ")
try:
    x = int(x)
    if x < 0:
        raise InputError(f'!!! x = input({x})', 
                         '-> Допустимы только положительные числа.')
except ValueError:
    print("Error type of value!")
except InputError as e:
    print(e.args[0])
    print(e.args[1])
else:
    print(x)


# Ведите положительное целое число: 3
# 3

# Ведите положительное целое число: 7.9
# Error type of value!

# Ведите положительное целое число: -5
# !!! x = input(-5)
# -> Допустимы только положительные числа.

У объектов класса исключений Exception и его производных, определен метод __str__() так, чтобы выводить значения атрибутов. Поэтому можно не обращаться напрямую к полям объекта: e.expression и e.message. Кроме того у экземпляров класса исключений Exception есть атрибут args. Через него можно получать доступ к отдельным полям, как показано в примере выше.

Многие стандартные модули определяют свои собственные исключения для сообщений об ошибках, которые могут возникать в определяемых ими функциях. Более подробная информация о классах представлена в разделе «Классы в Python».

Настройка собственных классов исключений.

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

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

Рассмотрим пример:

class SalaryNotInRangeError(Exception):
    """Исключение возникает из-за ошибок в зарплате.

    Атрибуты:
        salary: входная зарплата, вызвавшая ошибку
        message: объяснение ошибки
    """

    def __init__(self, salary, message="Зарплата не входит в диапазон (5000, 15000)"):
        self.salary = salary
        self.message = message
        # переопределяется конструктор встроенного класса `Exception()`
        super().__init__(self.message)


salary = int(input("Введите сумму зарплаты: "))
if not 5000 < salary < 15000:
    raise SalaryNotInRangeError(salary)

В примере, для приема аргументов salary и message переопределяется конструктор встроенного класса Exception(). Затем конструктор родительского класса Exception() вызывается вручную с аргументом self.message при помощи функции super(). Пользовательский атрибут self.salary определен для использования позже.

Результаты запуска скрипта:

Введите сумму зарплаты: 2000
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    raise SalaryNotInRangeError(salary)
__main__.SalaryNotInRangeError: Зарплата не входит в диапазон (5000, 15000)

Унаследованный метод __str__ класса Exception() используется для отображения соответствующего сообщения при возникновении SalaryNotInRangeError(). Также можно настроить сам метод __str__, переопределив его.

class SalaryNotInRangeError(Exception):
    """Исключение возникает из-за ошибок в зарплате.

    Атрибуты:
        salary: входная зарплата, вызвавшая ошибку
        message: объяснение ошибки
    """

    def __init__(self, salary, message="Зарплата не входит в диапазон (5000, 15000)"):
        self.salary = salary
        self.message = message
        super().__init__(self.message)

    # переопределяем метод '__str__'
    def __str__(self):
        return f'{self.salary} -> {self.message}'

salary = int(input("Введите сумму зарплаты: "))
if not 5000 < salary < 15000:
    raise SalaryNotInRangeError(salary)

Вывод работы скрипта:

Введите сумму зарплаты: 2000
Traceback (most recent call last):
  File "test.py", line 20, in <module>
    raise SalaryNotInRangeError(salary)
__main__.SalaryNotInRangeError: 2000 -> Зарплата не входит в диапазон (5000, 15000)

Как перехватывать пользовательское исключение.

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

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

import sqlite3 

class MyError(Exception):
     """Could not connect to db"""
     pass

try:         
    conn= sqlite3.connect('database.sqlite')
except sqlite3.Error as e:
    raise MyError(f'Could not connect to db: {e.value}')

В примере ловиться исключение, определяемое модулем sqlite3, а затем вызывается пользовательское исключение при помощи raise.

Prerequisite: This article is an extension to Exception Handling.

In this article, we will try to cover How to Define Custom Exceptions in Python with Examples. 

Example: 

class CustomError(Exception):
    pass

raise CustomError("Example of Custom Exceptions in Python")

Output: CustomError: Example of Custom Exceptions in Python

Python throws errors and exceptions when the code goes wrong, which may cause the program to stop abruptly. Python also provides an exception handling method with the help of try-except. Some of the standard exceptions which are most frequent include IndexError, ImportError, IOError, ZeroDivisionError, TypeError, and FileNotFoundError.

User-Defined Exception in Python

Exceptions need to be derived from the Exception class, either directly or indirectly. Although not mandatory, most of the exceptions are named as names that end in “Error” similar to the naming of the standard exceptions in python. For example,

Python3

class MyError(Exception):

    def __init__(self, value):

        self.value = value

    def __str__(self):

        return(repr(self.value))

try:

    raise(MyError(3*2))

except MyError as error:

    print('A New Exception occurred: ', error.value)

Output

A New Exception occurred:  6

Customizing Exception Classes

To know more about class Exception, run the code below 

Python3

Output

Help on class Exception in module exceptions:

class Exception(BaseException)
 |  Common base class for all non-exit exceptions.
 |  
 |  Method resolution order:
 |      Exception
 |      BaseException
 |      __builtin__.object
 |  
 |  Methods defined here:
 |  
 |  __init__(...)
 |      x.__init__(...) initializes x; see help(type(x)) for signature
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from BaseException:
 |  
 |  __delattr__(...)
 |      x.__delattr__('name') <==> del x.name
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __getslice__(...)
 |      x.__getslice__(i, j) <==> x[i:j]
 |      
 |      Use of negative indices is not supported.
 |  
 |  __reduce__(...)
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __setattr__(...)
 |      x.__setattr__('name', value) <==> x.name = value
 |  
 |  __setstate__(...)
 |  
 |  __str__(...)
 |      x.__str__() <==> str(x)
 |  
 |  __unicode__(...)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from BaseException:
 |  
 |  __dict__
 |  
 |  args
 |  
 |  message

Example 1: User-Defined class with Multiple Inheritance

In the below article, we have created a class named “Error” derived from the class Exception. This base class is inherited by various user-defined classes to handle different types of python raise an exception with message

Python3

class Error(Exception):

    pass

class zerodivision(Error):

    pass

try:

    i_num = int(input("Enter a number: "))

    if i_num == 0:

        raise zerodivision

except zerodivision:

    print("Input value is zero, try again!")

    print()

Output

Enter a number: 0
Input value is zero, try again!

Example 2: Deriving Error from Super Class Exception

Superclass Exceptions are created when a module needs to handle several distinct errors. One of the common ways of doing this is to create a base class for exceptions defined by that module. Further, various subclasses are defined to create specific exception classes for different error conditions.

Python3

class Error(Exception):

    pass

class TransitionError(Error):

    def __init__(self, prev, nex, msg):

        self.prev = prev

        self.next = nex

        self.msg = msg

try:

    raise(TransitionError(2, 3*2, "Not Allowed"))

except TransitionError as error:

    print('Exception occurred: ', error.msg)

Output

Exception occurred:  Not Allowed

How to use standard Exceptions as a base class?

A runtime error is a class that is a standard exception that is raised when a generated error does not fall into any category. This program illustrates how to use runtime error as a base class and network error as a derived class. In a similar way, an exception can be derived from the standard exceptions of Python.

Python3

class Networkerror(RuntimeError):

    def __init__(self, arg):

        self.args = arg

try:

    raise Networkerror("Error")

except Networkerror as e:

    print(e.args)

Output

('E', 'r', 'r', 'o', 'r')

Last Updated :
15 Mar, 2023

Like Article

Save Article

An Exception is raised whenever there is an error encountered, and it signifies that something went wrong with the program. By default, there are many exceptions that the language defines for us, such as TypeError when the wrong type is passed. In this article, we shall look at how we can create our own Custom Exceptions in Python.

But before we take a look at how custom exceptions are implemented, let us find out how we could raise different types of exceptions in Python.


Raise Exceptions

Python allows the programmer to raise an Exception manually using the raise keyword.

Format: raise ExceptionName

The below function raises different exceptions depending on the input passed to the function.

def exception_raiser(string):
    if isinstance(string, int):
        raise ValueError
    elif isinstance(string, str):
        raise IndexError
    else:
        raise TypeError

Output:

>>> exception_raiser(123)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in exception_raiser
ValueError
>>> exception_raiser('abc')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in exception_raiser
IndexError
>>> exception_raiser([123, 456])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in exception_raiser
TypeError

As you can observe, different types of Exceptions are raised based on the input, at the programmer’s choice. This allows for good flexibility of Error Handling as well, since we can actively predict why an Exception can be raised.


Defining Custom Exceptions

Similarly, Python also allows us to define our own custom Exceptions. We are in complete control of what this Exception can do, and when it can be raised, using the raise keyword. Let us look at how we can define and implement some custom Exceptions.

1. Create a Custom Exception Class

We can create a custom Exception class to define the new Exception. Again, the idea behind using a Class is because Python treats everything as a Class. So it doesn’t seem that outlandish that an Exception can be a class as well!

All Exceptions inherit the parent Exception Class, which we shall also inherit when creating our class.

We shall create a Class called MyException, which raises an Exception only if the input passed to it is a list and the number of elements in the list is odd.

class MyException(Exception):
	pass

def list_check(lst):
    if len(lst) % 2 != 0:
        raise MyException

# MyException will not be raised
list_check([1, 2, 3, 4])

# MyException will be raised
list_check([1, 3, 5])    

Output:

[email protected]:~# python3 exceptions.py
Traceback (most recent call last):
  File "exceptions.py", line 12, in <module>
    list_check([1, 3, 5])
  File "exceptions.py", line 6, in list_check
    raise MyException
__main__.MyException

2. Add a custom Message and Error

We can add our own error messages and print them to the console for our Custom Exception. This involves passing two other parameters in our MyException class, the message and error parameters.

Let us modify our original code to account for a custom Message and Error for our Exception.

class MyException(Exception):
    def __init__(self, message, errors):
        # Call Exception.__init__(message)
        # to use the same Message header as the parent class
        super().__init__(message)
        self.errors = errors
        # Display the errors
        print('Printing Errors:')
        print(errors)

def list_check(lst):
    if len(lst) % 2 != 0:
        raise MyException('Custom Message', 'Custom Error')

# MyException will not be raised
list_check([1, 2, 3, 4])

# MyException will be raised
list_check([1, 3, 5])

Output:

Printing Errors:
Custom Error
Traceback (most recent call last):
  File "exceptions.py", line 17, in <module>
    list_check([1, 3, 5])
  File "exceptions.py", line 11, in list_check
    raise MyException('Custom Message', 'Custom Error')
__main__.MyException: Custom Message

We have thus successfully implemented our own Custom Exceptions, including adding custom error messages for debugging purposes! This can be very useful if you are building a Library/API and another programmer wants to know what exactly went wrong when the custom Exception is raised.


Conclusion

In this article, we learned how to raise Exceptions using the raise keyword, and also build our own Exceptions using a Class and add error messages to our Exception.

References

  • JournalDev article on Custom Exceptions
  • Exception Handling in Python

Понравилась статья? Поделить с друзьями:
  • Кастомные ошибки java
  • Кассовый терминал ошибка 99
  • Кассовый аппарат элвис ошибка е 244
  • Кассовый аппарат элвес мф ошибка 244
  • Кассовый аппарат экватор ошибка 235