3 ms·
> “While recommended, with isn't always applicable. For example, assume you have an object that encapsulates some sort of a database that has to be committed an
by mlthoughts2018 8y ago
> “While recommended, with isn't always applicable. For example, assume you have an object that encapsulates some sort of a database that has to be committed and closed when the object ends its existence. Now suppose the object should be a member variable of some large and complex class (say, a GUI dialog, or a MVC model class). The parent interacts with the DB object from time to time in different methods, so using with isn't practical.”
This isn’t exactly true. One way to still use context managers is to mix them with coroutines, even simple generator functions.
For example, for something repeatedly interacting with s database, you may have a generator function with a non-terminating loop, that relies on generator `send` commands to resume the coroutine with a newly injected value. This can be used to repeatedly insert new data or repeatedly query, and then when a “close” sentinel is sent, it breaks the loop and the context manager automatically cleans up the connection. I’ve used this idea with manipulation of TensorFlow graphs too.
This only works well if it’s hidden behind a library function or other type of user friendly calling interface though. If you’re making the user manually deal with the generator function, they are as liable to make mistakes as of they are tasked with manually closing resources or designing a destructor.
- icegreentea2 8y agoI don't think using the generator solve's the author's specific problem which is to figure out when to send that "close" sentinel event. The author is looking for a way to "know" when an instance of a large and complex class is "done".
- mlthoughts2018 8y agoThis can be put in the object’s del method though, so that when the object holding the connection goes out of scope, it still uses a context manager as the means of cleaning up the resource. I agree this isn’t easy all the time, but it is a good trick for library writers, since you control del in that case and can design it this way so that del has no complex logic and the “real” mechanism is still just a behind the scenes context manager.
- ali_m 8y agoWhat would be the advantage over just having your __del__ method do the cleanup directly (rather than using a context manager)? You still suffer from most of the disadvantages of using __del__ - you have very few guarantees about when it will be called (if at all), and it may render your object un-garbage-collectable if there are cyclic references.
- mlthoughts2018 8y agoIn cases of resource cleanup you often (not always) don’t care so much about deterministic destruction, because holding onto the resource is not acting as a bottleneck and doesn’t lead to any performance or resource problem. In such a case, there’s a big win to avoiding writing custom destructor logic that adds complexity and requires more testing and so on. If you can use something super simple, like a context manager decorator or a simple generator function with a context manager inside, and the destructor logic is basically just “call close()” to trigger the implicit cleanup of the context manager, it’s often worth it. You aren’t writing much logic to specially process a “close” operation.. you’re just electing to let the thing containing the context manager go out of scope. But I do agree in a case where, for example, leaving many open connections to a resource would create a resource limit or bottleneck, then ensuring it happens deterministically is probably important.