What is the correct way to declare a custom exception class in modern Python? My main goal is to follow any standards that other exception classes have, so that any tool I catch in an exception, for example, prints out any extra strings I include in the exception.
"Modern Python" refers to a "right" way to run in Python 2.5 but for Python 2.6 and Python 3. *. The so-called "custom" refers to an Exception object, which can contain other data about the cause of the error: string, and perhaps any other object related to the Exception.
I stumbled in Python 2.6.2 with the following deprecation warnings:
>>> class MyError(Exception): ... def __init__(self, message): ... self.message = message ... >>> MyError("foo") _sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
BaseException seems crazy to have a special meaning for a property called message. I from PEP-352 Collected that the attribute does have a special meaning in 2.5, so they want to discard the attribute, so I guess the name (and a person) is now prohibited. Ah.
I also vaguely know that Exception has some magic parameters args, but I never know how to use it. I'm not sure it's the right way to move forward. Many of the discussions I've found online indicate that they're trying to eliminate args in Python 3.
Update: there are two answers suggested to override ﹐ init ﹐ and ﹐ str ﹐ / ﹐ Unicode ﹐ / ﹐ repr ﹐. It's like a lot of writing. Is it necessary?
#1 building
With modern Python exceptions, you don't need to abuse. Message, or override. str or. repr or anything. If all you want is a prompt message when an exception is thrown, do the following:
class MyException(Exception): pass raise MyException("My hovercraft is full of eels")
This will trace back to MyException: My hovercraft is full of eels at the end of MyException: My hovercraft is full of eels.
If you want more flexibility from exceptions, you can pass a dictionary as a parameter:
raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
However, getting these details in the except block is a little more complicated. Details are stored in the args attribute, which is a list. You will need to do the following:
try: raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"}) except MyException as e: details = e.args[0] print(details["animal"])
You can still pass multiple items to exceptions and access them through the tuple index, but it is highly recommended that you do not (even intend to discard them in the near future). If you do need more than one piece of information, and the above methods are not enough to meet your requirements, you should follow this Tutorials Describes subclassing an Exception.
class MyError(Exception): def __init__(self, message, animal): self.message = message self.animal = animal def __str__(self): return self.message
#2 building
Instead of using message, you should override the method "repr" or "unicode". The args provided when constructing an exception will be in the args attribute of the exception object.
#3 building
Maybe I missed the question, but why not?
class MyException(Exception): pass
Edit: to overwrite something (or pass extra args):
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
This way, you can pass the dictionary of the error message to the second parameter and reach it later using e.errors.
Python 3 Update: in Python 3 +, you can use a more compact use of super():
class ValidationError(Exception): def __init__(self, message, errors): # Call the base class constructor with the parameters it needs super().__init__(message) # Now for your custom code... self.errors = errors
#4 building
No, messages are not forbidden. It's just out of date. Your application can use messages normally. But, of course, you can get rid of depreciation mistakes.
When creating custom Exception classes for applications, many of them inherit not only subclasses from Exception, but also from other subclasses such as ValueError. Then, you have to adapt to their use of variables.
Also, if you have many exceptions in your application, it is usually best to have a common custom base class for all exceptions so that users of the module can
try: ... except NelsonsExceptions: ...
In that case, you can do the init and STR required there, so you don't have to repeat this for each exception. But simply calling the message variable instead of message solves the problem.
In any case, if you do something different from the Exception itself, you only need to either init or str. And because if you don't approve, you'll need both, or you'll make a mistake. Each class does not need a lot of extra code. ()
#5 building
See how exceptions work by default. If a VS is used with multiple attributes (traceback):
>>> raise Exception('bad thing happened') Exception: bad thing happened >>> raise Exception('bad thing happened', 'code is broken') Exception: ('bad thing happened', 'code is broken')
Therefore, you may need an exception template to work as the exception itself in a compatible way:
>>> nastyerr = NastyError('bad thing happened') >>> raise nastyerr NastyError: bad thing happened >>> raise nastyerr() NastyError: bad thing happened >>> raise nastyerr('code is broken') NastyError: ('bad thing happened', 'code is broken')
Use this subclass to do this easily
class ExceptionTemplate(Exception): def __call__(self, *args): return self.__class__(*(self.args + args)) # ... class NastyError(ExceptionTemplate): pass
If you don't like the default tuple like representation, just add the \\\\\\\\\\
# ... def __str__(self): return ': '.join(self.args)
Then you will
>>> raise nastyerr('code is broken') NastyError: bad thing happened: code is broken