Python api design robust cleanup and easy to use interpreter
I am working on python based API design. At the moment, I have encountered a problem with two different requirements. On the one hand, I would like to provide a reliable way to clean up API related resources. Thus, as I know, the best way to do it is to use context managers like:
# lib
class Client(object):
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, tb):
do_cleanup()
def method1(self):
pass
def method2(self):
pass
# api user
import mylib
with mylib.Client() as client:
client.method1()
client.method2()
On the other hand, I would like to suggest a way to use my library seamlessly in an interactive interpreter. But using a complex type construct with
or try-except-finally
in the interpreter makes using the interpreter less groovy because with
-block is treated as a single statement. And it would be preferable to use a single statement for one api method like:
# interpreter session
>>> import mylib
>>> client = mylib.Client()
<client object at ...>
>>> client.method1()
True
>>> client.method2()
100
So, can I have any options here? There is definitely a way to provide different semantics of use for scripts and for the interpreter, but I would like to use it as a last resort.
source to share
The typical way to do this is to provide a manual cleanup method and call __exit__
that method. For your example, if it do_cleanup
was implemented as a method, you can simply call it from the interpreter when you're done with it.
class Client(object):
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, tb):
self.do_cleanup()
def do_cleanup(self):
pass
def method1(self):
pass
def method2(self):
pass
Then in the interpreter
>>> import mylib
>>> client = mylib.Client()
<client object at ...>
>>> client.method1()
True
>>> client.method2()
100
>>> client.do_cleanup()
I would recommend renaming do_cleanup
to close
or similar, so the similarities between File Objects are more obvious.
source to share
You can create your own "base" logic with functions open
and close
in the implementation module and extend these classes using the context manager:
#in private module mymodule.impl
class Base(object):
def open(self, ...):
...
def close(self):
...
This file is usually not included in client code.
Instead, the client code imports exported.api
, which looks like this:
#in public package mymodule
import mymodule.impl
class Base(mymodule.impl.Base):
def __enter__(self):
return self
def __exit__(self, ...):
self.close()
source to share