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.

+3


source to share


2 answers


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.

+2


source


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()

      

0


source







All Articles