Python导入和提供可选特性的最佳实践是什么?

2024-05-19 17:38:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在github上写一个软件。它基本上是一个托盘图标,有一些额外的功能。我想提供一段有效的代码,而不需要让用户安装那些本质上依赖于可选功能的东西,我也不想导入我不打算使用的东西,所以我认为这样的代码是“好的解决方案”:

---- IN LOADING FUNCTION ----
features = []

for path in sys.path:
       if os.path.exists(os.path.join(path, 'pynotify')):
              features.append('pynotify')
       if os.path.exists(os.path.join(path, 'gnomekeyring.so')):
              features.append('gnome-keyring')

#user dialog to ask for stuff
#notifications available, do you want them enabled?
dlg = ConfigDialog(features)

if not dlg.get_notifications():
    features.remove('pynotify')


service_start(features ...)

---- SOMEWHERE ELSE ------

def service_start(features, other_config):

        if 'pynotify' in features:
               import pynotify
               #use pynotify...

但也有一些问题。如果用户格式化机器并安装最新版本的操作系统并重新部署此应用程序,则功能会在没有警告的情况下突然消失。解决方案是在配置窗口中显示:

if 'pynotify' in features:
    #gtk checkbox
else:
    #gtk label reading "Get pynotify and enjoy notification pop ups!"

但是如果这是一个mac,我怎么知道我没有让用户去寻找他们永远无法填补的依赖呢?

第二个问题是:

if os.path.exists(os.path.join(path, 'gnomekeyring.so')):

问题。我能确定这个文件在所有的linux发行版中都被称为gnomekeyring.so吗?

其他人如何测试这些功能?基本问题

try:
    import pynotify
except:
    pynotify = disabled

是因为代码是全局的,这些代码可能乱七八糟,即使用户不想使用pynotify……它还是被加载了。

那么人们认为解决这个问题的最好方法是什么呢?


Tags: path代码用户in功能forifso
3条回答

处理不同特性的不同依赖性问题的一种方法是将可选特性作为插件实现。这样,用户可以控制应用程序中激活的功能,但不负责自己跟踪依赖项。然后在每个插件安装时处理该任务。

try:方法不需要是全局的,它可以在任何范围内使用,因此模块可以在运行时“延迟加载”。例如:

def foo():
    try:
        import external_module
    except ImportError:
        external_module = None 

    if external_module:
        external_module.some_whizzy_feature()
    else:
        print("You could be using a whizzy feature right now, if you had external_module.")

运行脚本时,不会尝试加载external_module。第一次调用foo()时,external_module(如果可用)被加载并插入到函数的本地作用域中。对foo()的后续调用将external_module重新插入到其作用域中,而无需重新加载模块。

一般来说,最好让Python处理导入逻辑—它已经做了一段时间了。:-)

您可能需要查看imp module,它基本上完成了上面手动执行的操作。因此,您可以首先查找带有find_module()的模块,然后通过load_module()加载它,或者只需导入它(在检查配置之后)。

顺便说一句,如果使用except:我总是将特定的异常添加到它(这里是ImportError)中,以避免意外捕获不相关的错误。

相关问题 更多 >