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

«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 ?

Many object-oriented programming languages support using and handling “built-in” exceptions and writing custom exceptions for user-defined classes and packages. Writing and raising custom exceptions in Python is very easy to do. But before you read how to do it and then go off to try it, let me set your expectations a bit differently by way of a helpful metaphor:

Writing custom exceptions is really easy — as easy as a two-year-old crossing the street.

Now that I have frightened you enough for more than one article, let me hasten to reassure you that just going off and writing some custom exceptions, even if you don’t need them, won’t get you run over. You might suffer some temporary embarrassment over a pull request. At worst, it might make your code harder to maintain than it might be otherwise.

Nevertheless, the point of this article is not just to point you at the street and hope for the best but to share how we might “look both ways first” to improve our code. Here’s how it will break down.

In part one, Creating Custom Exceptions, I will acknowledge the time-honored development practice of letting go of mom’s hand and running out in the street.

In the second part, Custom Exception Best Practices, I’ll share some best practices to consider. I was the developer equivalent of a two-year-old once, so in this section, I will try to write the article I needed at the time.

Creating Custom Exceptions

The Custom Exception Class

We all hate it when our favorite food goes missing, so let’s model the unfortunate case where we have run out of something.

class RanOutOfSomething(Exception):
    pass

That was too easy. We’ve written a custom exception in two lines of code, and the second line was just to let Python know that we finished declaring our RanOutOfSomething exception class. By the way, an alternative syntax is to use a docstring here:

class RanOutOfSomething(Exception):
    """The cupboard is bare."""

Either way, the real work is done on the first line. We declare a class as a child of Python’s built-in Exception, and we’re done.

Raising Custom Exceptions

Raising (throwing) such an exception is even easier than creating them. We use the same mechanism (raise) as we would for a built-in exception. Here’s how that looks in Jupyter:

Further Customizing Exception Behavior with __init__:

I’m a big fan of simple exception classes like RanOutOfSomething that take a string because they assume that the code raising the error has the best insight into what went wrong. This idiom is common in the Python community, too. Packages that use it include NumPy and boto3.

To give you an idea of how you might further customize the behavior if you needed to, however, let’s write a more complex version of RanOutOfSomething, which will call NoMoreSomethingException, which will do the following:

  • If called with a string, it will use the default.
  • If called with nothing, it will embarrass you. This code enforces telling the user what went wrong.
  • If called with an optional value, “what,” it will format that into a standard error message.

I’ll warn you upfront that this code is likely about 98% more complicated than you need, but that said, here it is:

class NoMoreSomethingException(Exception):
    """A flexible reminder to go to the store.
       
       Can be called with a full string or with "what" parameter to get a default message, e.g.
       
           NoMoreSomethingException("We're out of polar ice caps. Bring a boat.")
           NoMoreSomethingException(what="cheese")                  
    """
    def __init__(self, message=None, what=None):
        if what is not None:
            msg = f"We're out of {what}."
        elif message is None:
            msg = "An inconsiderate colleague ran out of something.  Go look in the source; he hates you."
        else:
            msg = message
        super(NoMoreSomethingException, self).__init__(msg)

To test this out, we don’t necessarily have to raise the error. Since exceptions are just classes, we can see how they will appear by using print along with the repr function.

ex1 = NoMoreSomethingException("We're out of coffee! Development work cannot continue!!!")
ex2 = NoMoreSomethingException(what=["apple juice", "Pop Tarts"])

print(repr(ex1))
print(repr(ex2))

# Don't do this:
bad = NoMoreSomethingException()
print(repr(bad))


## OUTPUTS

NoMoreSomethingException("We're out of coffee! Development work cannot continue!!!")
NoMoreSomethingException("We're out of ['apple juice', 'Pop Tarts'].")
NoMoreSomethingException('An inconsiderate colleague ran out of something and is making you read the source to find out what it is.')

By the way, if you still need to hide the government secret of what we ran out of, NoMoreSomethingException("") gets you there.

Of course, you can do many other customizations, for example, overriding dunder methods or supporting the numerical error codes that some downstream system returns. However, the clarity of the exception name and a customizable message string is often 99% of what you need.

With that said, you now know where the street is. In our next section, let’s discuss how we can look both ways before crossing.

Python Custom Exception Best Practices

In this section, we want to discuss three things you should consider before implementing custom exception classes in Python.

  • Understanding the existing exception hierarchy in Python and where custom exceptions fit in.
  • Deciding if we even need custom exceptions, or whether we can use the built-in exception classes.
  • Thinking about additional design considerations if we are using custom exceptions.

User Defined Exceptions vs. Built-In Exceptions

As we’ve seen above, when we create user-defined exceptions in Python, we derive our custom class from Exception, not from BaseException. The informal class diagram below gives an overview of how the different classes fit together.

The Python documentation advises that custom exceptions should derive from Exception, not BaseException. To give you an idea of why this is so, consider two of the other classes derived from BaseException: SystemExit and KeyboardInterrupt. As the names imply, these are very low-level classes that we might handle, but generally wouldn’t need to override.

As we show here, the Exception class is a bit of a chameleon. It forms the basis of several important built-in classes on the one hand, and on the other, it is the right place to begin to define our user-defined exception classes.

On the built-in exception side on the left, many classes in Python derive from OSError. Moreover, several earlier classes have been reworked as aliases of OSError as of Python 3.3. For example, in newer versions of Python IOError == OSError evaluates to True! There are other classes here as well, however. Here is a more complete hierarchy chart for the built-in exceptions.

On the right-hand side of the chart image above, we show a possible user-defined class hierarchy. As shown here, this could be done as a common base class at the root with other classes derived from it. We’ll discuss this in a later section on class design. Before we discuss what the design should be, however, let’s first discuss the issue of whether you even need to design anything at all.

YAGNI: You Ain’t Gonna Need It

I think the best question you can ask yourself to decide if you really need one or more custom exceptions in your code is this one: Am I writing an application or a library?

If you’re writing a library, then there’s a very good chance that custom exception classes make sense. You want your users to be able to distinguish between an error in using your library and an error taking place somewhere else.

However, for every library developer, there are dozens if not hundreds of end users who are developing Python applications, doing data analytics, working in DevOps — or doing any number of other useful things with Python. If this is you, it’s quite possible that you can get by on a small number of built-in exceptions plus whatever the exceptions defined in whatever libraries you might be using.

For example, the best practice of checking function inputs can often be handled with two built-in exceptions. A TypeError can be used to remind the user of the correct type if they pass the wrong one to a function, while a ValueError can be raised if the type is correct but the value is out of range or can’t be supported — for example, a two-digit month that’s less than one or greater than twelve. To document that your code has encountered some other condition that you thought would never, ever in a zillion years happen (but of course does the day after you ship, lucky you), a simple Exception is sufficient. If you’re going to be working seriously in Python, it’s worth a few minutes of your time to read through the documentation on the Python exception classes so you understand what’s available.

Of course, even within an application, it’s possible you may want to define a very small number of custom exceptions to mark errors that occurred at a certain layer. For example, you may want to distinguish errors taking place in the model from those happening in the controller. However, if you’ve structured your code well, the stack trace should provide that same information without resorting to custom exception classes.

Design Decisions

We’ve been discussing aspects of exception design all along. We generally want a simple override unless we need further customization such as reporting an underlying error. This is common practice in HTTP libraries for example, where we might want the string response “Not Found” and the appropriate HTTP status code, 404.

The only final thing to consider, then, is the issue of having a single root exception class or not for your library. Different libraries take different approaches to this. The Pandas library derives each custom exception directly from Python’s Exception class, in an ad-hoc fashion, for example.

Since I haven’t seen too many notebooks that wrap their Pandas code in try/except blocks, that’s probably not a big problem. The more commonly scripted client library for Amazon Web Services, boto3, takes the alternative approach of having a common root exception, Boto3Error, from which all other exceptions are derived. This makes it easy to add error handling any time you make a call, which I think works really well for a client library like this.

Closing Thoughts

Software developers love grand designs and framework development because sometimes that can be a lot more interesting than the day-to-day grunt work of shipping products. Python custom exceptions are easy to add, but chances are we don’t need them if we’re working on an application. If that’s the case, the best thing we can do for our users is to use well-known exceptions together with an error string providing detailed information about how to resolve the issue.

The true gold standard here is not whether we can cleverly override a Python constructor, but whether someone who is the unfortunate exception of a late-night support call can read the exception message and have a reasonable chance of being able to address the issue and go back to sleep.

I realize I’m on a bit of a soapbox here.

raise FellOffSoapBoxError("Thanks for reading!")

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

В 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.

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