6

我正在使用cffi.

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 端不是一个大问题)。

这些路径中的哪一个更符合 Python 风格?

4

1 回答 1

4

仅当库实际上支持一个应用程序中的多个实例之类的东西时,才在 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 的更多详细信息,此问题有更多详细信息,当然还有python 文档

于 2015-06-05T18:37:55.140 回答