2013-06-27 106 views
5

我正在爲使用cffi的C庫編寫一個Python包裝器。Python模塊中的全局狀態

C庫必須被初始化並關閉。另外,cffi需要一些地方來保存從ffi.dlopen()返回的狀態。

我可以看到兩個路徑在這裏:

要麼我把這個包整個狀態的企業在一類這樣的

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

或者我提供了隱藏在一個全局變量的狀態兩個全局函數

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

第一個路徑有點麻煩,因爲它要求用戶總是創建一個對象,除了管理lib拉里狀態。另一方面,它確保每次都調用terminate()

第二條路徑似乎導致了一個更簡單的API。但是,它暴露了一些隱藏的全球狀態,這可能是一件壞事。另外,如果用戶忘記調用terminate(),C庫不能正確卸載(這在C方面並不是很大的問題)。

這些路徑中哪一個會變得更加pythonic?

+1

任何原因導致模塊不僅僅是初始化庫(並在模塊全局變量中存儲必要的引用)? – kindall

+0

@kindall然後我會怎麼調用terminate()呢? – bastibe

+1

你說這沒有什麼大不了的。但是如果需要調用,那麼唯一可行的方法是讓庫的用戶調用它。反正你不能指望'__del__'。上下文管理器可能有意義,但是... – kindall

回答

3

暴露包裝對象只有在python中才有意義,如果庫實際上在一個應用程序中支持類似多個實例的東西。如果它不支持,或者它不是真正相關的,那麼去kindall的建議,並在導入時初始化庫並添加一個atexit處理程序進行清理。

在沒有支持保持不同狀態集的情況下添加無狀態API或甚至API的包裝並不是真正的pythonic,並且會提高對不同實例有某種隔離的期望。

示例代碼:

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) 

有關的atexit this question詳情有一些更多細節,有當然python documentation