2013-06-27 11 views
5

Piszę wrapper Pythona dla biblioteki C używając cffi.Stan globalny w module Python

Biblioteka C musi zostać zainicjalizowana i wyłączona. Ponadto, cffi potrzebuje miejsca, aby zapisać stan zwrócony z ffi.dlopen().

widzę dwie ścieżki tutaj:

Albo ja owinąć całą tę stanową działalność w klasie jak ten

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

Albo dostarczyć dwa globalne funkcje, które ukrywają stanu w zmiennej globalnej

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

Pierwsza ścieżka jest nieco uciążliwa, ponieważ wymaga, aby użytkownik zawsze tworzył obiekt, który naprawdę nie służy niczemu innemu niż zarządzanie biblioteką stan rary. Z drugiej strony zapewnia, że ​​terminate() jest rzeczywiście wywoływany za każdym razem.

Druga ścieżka wydaje się powodować nieco łatwiejszy interfejs API. Jednak ujawnia jakiś ukryty stan globalny, co może być złe. Ponadto, jeśli użytkownik zapomni zadzwonić pod numer terminate(), biblioteka C nie jest poprawnie rozładowywana (co nie jest dużym problemem po stronie C).

Która z tych ścieżek byłaby bardziej pytoniczna?

+1

Dowolny powód nie tylko zainicjowania biblioteki po zaimportowaniu modułu (i zapisaniu niezbędnych odniesień w globalizatorze modułów)? – kindall

+0

@ linux jak mam nazwać 'zakończ()', a następnie? – bastibe

+1

Powiedziałeś, że to nie jest wielka sprawa, jeśli nie zostanie to wywołane. Ale jeśli wymaga wywoływania, jedynym sposobem, aby to zrobić niezawodnie, jest wywołanie go przez użytkownika biblioteki. W każdym razie nie możesz liczyć na '__del__'. Menedżer kontekstu może mieć sens, chociaż ... – kindall

Odpowiedz

3

Ekspozycja obiektu opakowującego ma sens tylko w pythonie, jeśli biblioteka faktycznie obsługuje coś takiego jak wiele instancji w jednej aplikacji. Jeśli nie obsługuje tego lub nie jest to naprawdę istotne, przejdź do sugestii rodzaju i po prostu zainicjuj bibliotekę po zaimportowaniu i dodaj procedurę obsługi atexit do czyszczenia.

Dodanie otoków wokół bezpaństwowego api lub nawet api bez wsparcia dla utrzymywania różnych zestawów stanów nie jest tak naprawdę pythonic i podniosłoby oczekiwania, że ​​różne instancje mają pewien rodzaj izolacji.

Przykład Kod:

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) 

Więcej szczegółów o atexit this question zawiera więcej szczegółów, co ma python documentation oczywiście.