Handle exception in __init__

exception, python

Solution

It is perfectly fine to raise an exception in `__init__`. You would then wrap the object initiation/creation call with `try/except` and react to the exception.

One potential odd result though is that `__del__` is run anyway:

class Demo(object):
    def __init__(self, value):
        self.value=value
        if value==2:
            raise ValueError
    def __del__(self):
        print '__del__', self.value


d=Demo(1)     # successfully create an object here
d=22          # new int object labeled 'd'; old 'd' goes out of scope
              # '__del__ 1' is printed once a new name is put on old 'd'
              # since the object is deleted with no references 

Now try with the value `2` that we are testing for:

Demo(2)
Traceback (most recent call last):
  File "Untitled 3.py", line 11, in <module>
    Demo(2)           
  File "Untitled 3.py", line 5, in __init__
    raise ValueError
  ValueError
 __del__ 2 # But note that `__del__` is still run.

The creation of the object with value `2` raises a `ValueError` exception and show that `__del__` is still run to clean up the object.

Keep in mind that if you raise an exception during `__init__` your object will not get a name. (It will, however, be created and destroyed. Since `__del__` is paired with `__new__` it still gets called)

ie, just like this does not create `x`:

>>> x=1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

Potential sneakier:

>>> x='Old X'
>>> x=1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> x
'Old X'

Same thing if you catch an exception of `__init__`:

try:
    o=Demo(2)
except ValueError:
    print o          # name error -- 'o' never gets bound to the object...
                     # Worst still -- 'o' is its OLD value!

So don't try to refer to the incomplete object `o` -- it's gone out of scope by the time you get to `except`. And the name `o` is either nothing (i.e., `NameError` if you try to use it) or its old value.

So wrapping up (thanks to Steve Jessop for the User Defined Exception idea), you can wrap the creation of the object and catch the exception. Just figure out how to react appropriately to the OS error you are looking at.

So:

class ForbiddenTwoException(Exception): 
    pass

class Demo(object):
    def __init__(self, value):
        self.value=value
        print 'trying to create with val:', value
        if value==2:
            raise ForbiddenTwoException
    def __del__(self):
        print '__del__', self.value

try:
    o=Demo(2)
except ForbiddenTwoException:
    print 'Doh! Cant create Demo with a "2"! Forbidden!!!'
    # with your example - react to being unusable to create a directory... 

Prints:

trying to create with val: 2
Doh! Cant create Demo with a "2"! Forbidden!!!
__del__ 2

Problem

Is it fine to raise an exception in `__init__` in python? I have this piece of code: ``` class VersionManager(object): def __init__(self, path): self._path = path if not os.path.exists(path): os.mkdir(path) myfunction(path) ``` The second line can potentially result in an exception. In that case the object will not be init'ed properly. Is there a better way to handle situations where code in `__init__` might throw an exception? EDIT Added a call to a function after `os.mkdir` Added a check to see if directory exists

Original source

Related problems