[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