Global state in Python module

De openkb
Aller à : Navigation, rechercher

Sommaire

Questions

I am writing a Python wrapper for a C library using the cffi.

The C library has to be initialized and shut down. Also, the cffi needs some place to save the state returned from ffi.dlopen().

I can see two paths here:

Either I wrap this whole stateful business in a class like this

class wrapper(object):
    def __init__(self):
        self.c = ffi.dlopen("mylibrary")
        self.c.initialize()
    def __del__(self):
        self.c.terminate()

Or I provide two global functions that hide the state in a global variable

def initialize():
    global __library 
    __library = ffi.dlopen("mylibrary")
    __library.initialize()
def terminate():
    __library.terminate()
    del __library

The first path is somewhat cumbersome in that it requires the user to always create an object that really serves no other purpose other than managing the library state. On the other hand, it makes sure that terminate() is actually called every time.

The second path seems to result in a somewhat easier API. However, it exposes some hidden global state, which might be a bad thing. Also, if the user forgets to call terminate(), the C library is not unloaded correctly (which is not a big problem on the C side).

Which one of these paths would be more pythonic?

Answers

Exposing a wrapper object only makes sense in python if the library actually supports something like multiple instances in one application. If it doesn t support that or it s not really relevant go for kindall s suggestion and just initialize the library when imported and add an atexit handler for cleanup.

Adding wrappers around a stateless api or even an api without support for keeping different sets of state is not really pythonic and would raise expectations that different instances have some kind of isolation.

Example code:

import atexit

# Normal library initialization
__library = ffi.dlopen("mylibrary")
__library.initialize()

# Private library cleanup function
def __terminate():
    __library.terminate()
# register function to be called on clean interpreter termination
atexit.register(__terminate)

https://docs.python.org/3/library/atexit.html https://docs.python.org/3/library/atexit.html

Source

License : cc by-sa 3.0

http://stackoverflow.com/questions/17346428/global-state-in-python-module

Related

Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Outils