Python context controlled control variable?

Context managers define the __enter__ and __exit__ configuration / cleanup __enter__ . Awesome. I want to save it as a member variable. When my class object goes out of scope, I want this cleanup to be performed. This is basically a behavior that, as I understand it, 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. 
+6
source share
2 answers

I provide a close classes if that 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 
+2
source

Python does not execute the C ++ RAII style ("Resource initialization is initialization," which means everything you get in the constructor you release in the destructor). In fact, there are almost no languages ​​except C ++ for C ++ - RAII style. Python context managers and with statements are another way of doing the same thing as C ++ 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 beyond"?

Objects do not go beyond; references (or variables or names, whatever you prefer). Some time after the last link goes out of scope (for CPython this happens immediately, unless it is involved in the reference loop, for other implementations it is usually absent), the object will be garbage collected.


If you want to do some cleanup when your objects are collected using garbage, you use the __del__ method for this. But this is rarely what you really want. (In fact, some classes have an __del__ method to warn users that they forgot to clear and not be silent.)


The best solution is to make Animal itself a context manager so that 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 is 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 away from the end of __exit__ , this means that after calling self.datafile.close() we do nothing if there was no exception, or re-raise the same exception if it is. "I need to write something- anything explicit for this to happen. "


But usually, if you are going to create a class in the context manager, you will also want to add an explicit close . Like files. And once you do this, you really don't need to make Animal into a context manager; you can just use closing .

+1
source

Source: https://habr.com/ru/post/978534/


All Articles