2009-02-18 79 views
18

我在github上写了一段软件。它基本上是一个带有一些额外功能的托盘图标。我想提供一段代码,而实际上并不需要让用户安装可选功能的本质依赖关系,而且我也不希望导入我不打算使用的东西,所以我认为这样的代码会“好的解决方案“:什么是Python导入和提供可选功能的好习惯?

---- 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!" 

但如果这是说,一个苹果,我怎么知道我不是在向用户发送关于白费力气寻找一个依赖他们可以永远填?

第二个问题是:

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

问题。我可以确定该文件始终在所有Linux发行版中都称为gnomekeyring.so吗?

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

try: 
    import pynotify 
except: 
    pynotify = disabled 

的问题是,代码是全球性的,这些可能会被周围散落并且即使用户不希望pynotify ....它无论如何加载。

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

回答

10

你可能想看看imp module,它基本上是你在上面手动做的。所以你可以先找一个带有find_module()的模块,然后通过load_module()或通过简单地导入它(在检查配置之后)加载它。

顺便说一句,如果使用除了:我总是会添加特定的异常(它在这里ImportError),以不意外地捕获无关的错误。

36

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

def foo(): 
    try: 
     import external_module 
    except ImportError: 
     pass 

    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处理导入逻辑 - 它已经做了一段时间。 :-)

+8

我认为`除了ImportError`块需要设置`external_module = None`,或者当你试图在if块中访问它时你会得到一个`NameError`。 – abhishekmukherg 2015-04-01 17:28:47

0

处理不同功能的不同依赖关系问题的一种方法是将可选功能实现为插件。这样用户就可以控制应用程序中的哪些功能被激活,但不负责追踪自己的依赖关系。那个任务然后在每个插件安装的时候被处理。