I'm writing a medium-complex Python program using PyOpenGL. OpenGL programming requires a lot of resources to be acquired, and I'm wondering how to manage their release.
From what I understand, e.g. in C++ a common strategy would be to have classes that wrap resources, which acquire the resource in their constructor and relase it in their destructor, the RAII idiom. RAII doesn't work well in Python, because destructors (actually, finalizers) are not deterministically called, as discussed e.g. here.
As pointed out there, the main facility in Python to manage resources is the with
statement and context managers. What I don't understand is how that scales to medium- to large programs, where the code using a resource is not a single suite of statements. The with
statement can replace the C++ mechanism of a local variable holding an object reference going out of scope, but not the C++ mechanism of an object field holding an object reference "expiring" when the object itself is destroyed.
For a simple example, let's say I have a class that when instantiated opens a file for writing, e.g. for logging. This file remains open throughout the object's (functional) existence and is written to in different methods. Because of writing spread over different methods, a with
statement is not applicable. So, how do I make sure the file is closed when the object is no longer used?
Do I make the class itself a context manager (implement __enter__
and __exit__
) and vow to use instances only via with
statements?
Or do I pair each __init__
method with a close
method and vow to always call this method when the object is no longer needed?
What is the Pythonic way?
I apologize if this question isn't particularly clear; that's because I'm trying to wrap my mind around something I don't clearly understand. I'd appreciate any comments on how to make it clearer.
Personal background: I'm not a C++ programmer and haven't done much OOP generally, but what I believe I understand about OOP is probably shaped by what I read about C++.