Context managers define setup/cleanup functions __enter__
and __exit__
. Awesome. I want to keep one around as a member variable. When my class object goes out of scope, I want this cleanup performed. This is basically the behavior that I understand happens automatically with C++ constructors/destructors.
class Animal(object):
def __init__(self):
self.datafile = open("file.txt") # This has a cleanup function
# I wish I could say something like...
with open("file.txt") as self.datafile: # uh...
def makeSound(self):
sound = self.datafile # I'll be using it later
# Usage...
if True:
animal = Animal()
# file should be cleaned up and closed at this point.
This module provides APIs to manage, store, and access context-local state. The ContextVar class is used to declare and work with Context Variables. The copy_context() function and the Context class should be used to manage the current context in asynchronous frameworks.
A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. with open('/path/to/file.txt', 'r') as f: for line in f: print(line)
__enter__() is provided which returns self while object. __exit__() is an abstract method which by default returns None .
I give classes a close
function if it makes sense and then use the closing
context manager:
class MyClass(object):
def __init__(self):
self.resource = acquire_resource()
def close():
release_resource(self.resource)
And then use it like:
from contextlib import closing
with closing(MyClass()) as my_object:
# use my_object
Python doesn't do C++-style RAII ("Resource Acquisition Is Initialization", meaning anything you acquire in the constructor, you release in the destructor). In fact, almost no languages besides C++ do C++-style RAII. Python's context managers and with
statements are a different way to achieve the same thing that C++ does with RAII, and that most other languages do with finally
statements, guard
statements, etc. (Python also has finally
, of course.)
What exactly do you mean by "When my class object goes out of scope"?
Objects don't go out of scope; references (or variables, or names, whatever you prefer) do. Some time after the last reference goes out of scope (for CPython, this is immediately, unless it's involved in a reference cycle; for other implementations, it's usually not), the object will be garbage-collected.
If you want to do some cleanup when your objects are garbage-collected, you use the __del__
method for that. But that's rarely what you actually want. (In fact, some classes have a __del__
method just to warn users that they forgot to clean up, rather than to silently clean up.)
A better solution is to make Animal
itself a context manager, so it can manage other context managers—or just manage things explicitly. Then you can write:
if True:
with Animal() as animal:
# do stuff
# now the file is closed
Here's an example:
class Animal(object):
def __init__(self):
self.datafile = open("file.txt")
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.datafile.close()
def makeSound(self):
sound = self.datafile # I'll be using it later
(Just falling off the end of __exit__
like that means that, after calling self.datafile.close()
, we successfully do nothing if there was no exception, or re-raise the same exception if there was one. So, you don't have to write anything explicit to make that happen.)
But usually, if you're going to make a class into a context manager, you also want to add an explicit close
. Just like files do. And once you do that, you really don't need to make Animal
into a context manager; you can just use closing
.
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