bas*_*ibe 6 python coding-style module global-variables
我正在使用C语言为C库编写Python包装器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()
Run Code Online (Sandbox Code Playgroud)
或者我提供两个全局函数来隐藏全局变量中的状态
def initialize():
global __library
__library = ffi.dlopen("mylibrary")
__library.initialize()
def terminate():
__library.terminate()
del __library
Run Code Online (Sandbox Code Playgroud)
第一条路径有点麻烦,因为它要求用户始终创建一个除了管理库状态之外没有其他目的的对象.另一方面,它确保terminate()
每次实际调用.
第二条路径似乎导致了一些更简单的API.然而,它暴露了一些隐藏的全局状态,这可能是一件坏事.此外,如果用户忘记调用terminate()
,则C库未正确卸载(这在C端不是一个大问题).
这些路径中的哪一条会更加pythonic?
仅当库实际上支持一个应用程序中的多个实例之类的东西时,公开包装对象才在 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)
Run Code Online (Sandbox Code Playgroud)
有关 atexit 的更多详细信息,这个问题有更多详细信息,当然还有python 文档。