I have searched and I\'m unable to come up with any good reason to use python\'s __enter__ /__exit__ rather than __init__ (or __new_
By using these instead of
__init__/__del__I appear to be creating an implicit contract with callers that they must usewith, yet there's no way to enforce such a contract
You have a contract either way. If users use your object without realizing it requires cleanup after use, they'll screw things up no matter how you implement the cleanup. They might keep a reference to your object forever, for example, preventing __del__ from running.
If you have an object that requires special cleanup, you need to make this requirement explicit. You need to give users with functionality and an explicit close or similar method, to let users control when the cleanup occurs. You can't hide the cleanup requirement inside a __del__ method. You might want to implement __del__ too, as a safety measure, but you can't use __del__ in place of with or an explicit close.
With that said, Python makes no promises that __del__ will run, ever. The standard implementation will run __del__ when an object's refcount drops to 0, but that might not happen if a reference survives to the end of the script, or if the object is in a reference cycle. Other implementations don't use refcounting, making __del__ even less predictable.