Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python context-managed member variable?

Tags:

python

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.
like image 483
user68331 Avatar asked Nov 22 '14 00:11

user68331


People also ask

What is context variable in Python?

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.

What is context manage in Python?

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)

What should __ exit __ return?

__enter__() is provided which returns self while object. __exit__() is an abstract method which by default returns None .


2 Answers

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
like image 171
Peter Wood Avatar answered Sep 23 '22 06:09

Peter Wood


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.

like image 38
abarnert Avatar answered Sep 22 '22 06:09

abarnert