Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call __exit__ method on exception during __init__?

Assume you have a class with defined __enter__ and __exit__ methods like so:

class MyClass:
    def f(self):
        raise Exception
    def __enter__(self): 
        return self
    def __exit__(self, type, value, traceback):
        pass

If an exception is raised inside the with block, like so:

with MyClass() as ins:
    ins.f()

The __exit__ method will be implicitly called, which is very nice.

However if your class is like this:

class MyClass:
    def __init__(self):
        self.f()
    def f(self):
        raise Exception
    def __enter__(self): 
        return self
    def __exit__(self, type, value, traceback):
        pass

And you instantiate it like so:

with MyClass() as ins:
    pass

When the exception is raised inside the __init__ method, __enter__ has yet to be called, and __exit__ goes uncalled as well, which is not so nice. What is the best way to remedy this?

like image 395
qwwqwwq Avatar asked Jul 01 '13 19:07

qwwqwwq


1 Answers

Obviously you cannot use a class that cannot be initiated as a context manager, so you have to create the instance before using it in the with block.

For example:

try:
    ins = MyClass()
except Exception as e: 
    print "Cant initiate MyClass"
else:
    with ins:
        pass

You can add extra resources by passing them to the Class instead of creating them during initiation:

with spawnResource() as res, MyClass(res) as y:
    print x,y
like image 162
Jochen Ritzel Avatar answered Oct 23 '22 04:10

Jochen Ritzel