简单的插件体系结构

到目前为止,我只讨论了如何使用这个工具,还没有解释这些插件的工作原理。先看看这个模块顶部的导入语句:

plugin_available = True
from plugin import *
from plugin import __all__ #note this is the registered plugin list
except ImportError:
plugin_available = False


这个导入语句揭示了这个极其简单的插件体系结构的秘密。一般情况下,Python 官方文档不鼓励使用“from package import *” 语法,但是如果有合理理由的话比如编写插件),可以这样做。插件作者负责在插件目录中的 __init__.py 文件中创建一个条目。这个条目应该像下面这样:

"""Lists all of the importable plugins"""
__all__ = ["move_to_tmp", "print_file_path_ext"] 

通过创建这个条目,可以以 * 的形式导入包或目录)中的所有模块。接下来,导入实际的 __all__ 列表,向用户显示可用的插件。最后,还需要一行代码。因为直到运行之前命令行工具并不知道要使用哪个插件动作,所以要使用 eval 把命令行上的动作字符串转换为一个可调用的函数,如下所示:

action_plugin = eval(arguments[1])


在一般情况下,应该极其谨慎地使用 eval,但是在这里通过 eval 告诉工具使用哪些插件方法是合理的。

插件示例分析

既然已经了解了这个插件体系结构的工作原理,就来看看实际的插件。注意,为了让这个体系结构发挥作用,需要在当前工作目录或 Python site-packages 目录中创建一个插件目录。我们要讨论的插件称为 print_file_path_ext.py,它包含一个称为 plug-in 的方法。这是插件开发人员必须满足的 API 要求。


清单 3. 插件示例

#!/usr/bin/env python
# encoding: utf-8
"""
prints path, name, ext, plugin
"""
def plugin(rec, verbose=True):
"""Moves matched files to tmp directory"""
path = rec["path"]
filename = rec["filename"]
ext = rec["ext"]
print "%s | %s | %s" % (path, filename, ext)

这个插件非常简单。它有一个 rec 参数,这个参数是 pathtool 模块生成的词典。这个词典包含以下 API:

{"path": path, "filename": file, "ext": ext, "size": size,
"unique_id": unique_id, "mtime": mtime, "ctime": ctime}

在这个示例中,每当调用它时,使用词典的键输出特定文件对象的值。插件作者可以编写许多更有用的动作,比如对文件进行转换、重命名、存档等等。

结束语

本文介绍了一个非常简单的插件体系结构,可以通过它用 Python 扩展命令行工具。但是,应该注意几点。首先,可以通过 easy_install 使用一个更高级的插件系统参见参考资料)。这个插件系统允许用户创建“入口点” 来为工具定义插件。第二,我们的命令行工具只允许一个“动作” 插件。可以修改这个命令行工具,让它能够接受数量不限的“链式” 回调动作,这留给读者作为练习。

关于创建链式插件还有一个问题:设计必须考虑到使用的 API 的性质。在我们的示例中,以生成器作为基础。为了让这个工具能够把插件“链接” 在一起,各个插件必须完成本身的工作,然后生成词典记录。我希望本文能够鼓励您为命令行工具编写自己的插件。

  1. 循序渐进学Python:安装、使用与运行程序
  2. 循序渐进学Python:三种选择语句
  3. 循序渐进学Python之函数入门
  4. 循序渐进学Python之函数的嵌套


评论关闭