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?
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
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With