Search code examples
pythonraiiwith-statement

Python with statements


I'm experimenting with Python's with statements, and I've found that in the following code listing my __init__ method gets called twice, while my __exit__ method gets called once. This presumably means that there will be a resource leak if this code did anything useful.

class MyResource:
    def __enter__(self):
        print 'Entering MyResource'
        return MyResource()

    def __exit__(self, exc_type, exc_value, traceback):
        print 'Cleaning up MyResource'

    def __init__(self):
        print 'Constructing MyResource'

    def some_function(self):
        print 'Some function'

def main():
    with MyResource() as r:
        r.some_function()

if __name__=='__main__':
    main()

This is the program's output:

Constructing MyResource
Entering MyResource
Constructing MyResource
Some function
Cleaning up MyResource

I'm guessing it's because I'm doing something wrong in the with statement, effectively calling the constructor manually. How do I correct this?


Solution

  • You shouldn't return a new instance from __enter__. Instead, return self (the instance for which __enter__ is being called. That's why __init__() is called twice -- you call it twice, once in your with statement, once in __enter__(). Here's a correct version:

    def __enter__(self):
        print 'Entering MyResource'
        return self