[Tutor] raising exceptions in constructor code?

Cameron Simpson cs at cskk.id.au
Tue Jul 16 19:17:41 EDT 2019


On 16Jul2019 23:49, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
>On 16/07/2019 22:56, Mats Wichmann wrote:
>>> thrown.  This gets watered down to the mantra "Don't throw 
>>> exceptions from
>>> within constructors."  Does this carry over to Python?
>>
>> If you mean __init__, that's not a constructor, so you should set your
>> mind at rest :)   It's more properly an "initializer", the instance has
>> already been constructed when it's called.
>
>FWIW The true constructor is __new__() and its quite rarely overridden
>by application programmers. But if you do, it's not common that you'd do
>anything that would merit an exception. __new__ pretty much just sets
>up the structure of the object ready for initialisation by __init__.
>
>Incidentally, this two stage construction/initialisation is also found
>in other OOP languages like Smalltalk and Objective C (and Lisp?).

And to return to the OP's question:

The __init__ method (and arguably __new__ if you touch it - very rare) 
is like other Python code: resource allocation should normally get 
unwound as objects become unreferenced. So raising an exception should 
be a pretty safe thing to do.

That is a simplification. Of course if you implement an object with side 
effects _outside_ the Python object space (maybe it opened a scratch 
file to support something), it is your responsibility to ensure release 
in the object's __del__ method. But an object that just allocates a 
bunch of lists or dicts or the like? Python will clean that up for you.

That said, I try to do cheap initialisation before exspensive 
initialisation. So allocating locks, opening files, starting worker 
threads: these come at the bottom of the __init__ method.

Also, it is _ROUTINE_ to raise exceptions from __init__: like any other 
method we _expect_ you to raise ValueError if the initialiser parameters 
are insane (negatively sized arrays, etc etc).

So in Python, raising exceptions in __init__ is normal: it shouldn't 
happen when you programme is running correctly of course, but it is the 
_preferred_ action when your initialiser cannot complete correctly.

Consider:

  x = Foo(....)

After this assignment we expect "x" to be a usable instance of Foo. We 
don't put special checks; what would such checks look like? (There are 
some answers for that, but they're all poor.)

So raising an exception is what happens if __init__ fails.

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Tutor mailing list