我正在使用cffi为C库编写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

第一条路径有些麻烦,因为它要求用户始终创建一个对象,除了管理库状态外,该对象实际上没有其他用途。另一方面,它可以确保每次实际上都调用terminate()

第二条路径似乎使API更加容易。但是,它暴露了一些隐藏的全局状态,这可能是一件坏事。另外,如果用户忘记调用terminate(),则C库不会正确卸载(在C端这不是大问题)。

这些路径中的哪一个更适合pythonic?

最佳答案

仅当库实际上在一个应用程序中支持多个实例之类时,才公开包装对象在python中才有意义。如果它不支持它,或者不真正相关,请引用kindall的建议,并在导入时初始化库,并添加atexit处理程序进行清理。

在无状态api甚至不支持保持不同状态集的api周围添加包装器并不是真正的Python,这会提高人们对不同实例具有某种隔离的期望。

示例代码:

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 questionpython documentation当然也有更多详细信息。

关于python - Python模块中的全局状态,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17346428/

10-11 22:04
查看更多