如何在不调用文件的情况下运行全局代码

时间:2015-09-16 18:46:41

标签: python

我正在编写一个python应用程序,允许用户编写自己的插件并扩展我提供的核心功能 -

$ tree project_dir/
.
├── application.py
├── plugins
│   ├── __init__.py
│   ├── example_plugin.py
│   ├── plugin1.py
│   ├── plugin2.py
│   └── plugin3
│       ├── sounds
│       │   └── test.wav
│       └── player.py
└── plugins_manager.py

plugins_manager.py -

class Manager(object):

    def __init__(self):
        self.plugins = {}

    def register_plugin(self, name, plugin_func):
        self.plugins[name] = plugin_func

application.py全局初始化Manager实例 -

manager = Manager()

def main():
    print manager.plugins

main()

每个插件都需要从Manager导入application.py实例并注册自己,如plugin1.py -

from application import manager

PLUGIN_NAME = "AAC_Player"

def plugin_function(options):
    # do something

manager.register_plugin(PLUGIN_NAME, plugin_function)

现在,当我运行application.py时,显然没有任何内容被打印出来。如何在程序启动时自己注册插件(调用.register_plugin())?

所以在这一行上,一个更普遍的问题是 - 如何让python执行一行代码,这些代码在文件中是全局的而不实际运行文件?

欢迎改进插件架构的建议!

2 个答案:

答案 0 :(得分:2)

您可以使用__import__()内置来导入插件,然后在插件文件register_plugin()example_plugin.py中包含__init__.py调用(如果它是目录)。

例如,假设这是您的项目结构:

./
application.py
plugins_manager.py
plugins/
    __init__.py
    plugin1.py
    plugin2.py
    plugin3/
        __init__.py

插件包含以下内容:

$ cat plugins/plugin1.py
print 'Plugin 1'

$ cat plugins/plugin2.py
print 'Plugin 2'

$ cat plugins/plugin3/__init__.py
print 'Plugin 3'

plugins_manager.py中,识别插件并将其导入:

from os import listdir
from os.path import exists, isdir, basename, join, splitext

def is_plugin(filename):
  filepath = join('plugins', filename)
  _, ext = splitext(filepath)

  # Ignore plugins/__init__.py
  if filename == '__init__.py':
    return False

  # Find single file plugins
  if ext == '.py':
    return True

  # Find plugins packaged in directories
  if isdir(filepath) and exists(join(filepath, '__init__.py')):
    return True

  return False

plugin_names = [ splitext(p)[0] for p in listdir('plugins/') if is_plugin(p) ]
plugins = [ __import__('plugins.' + p) for p in plugin_names ]

输出应该类似于:

Plugin 1
Plugin 2
Plugin 3

请注意,在这种情况下,plugins变量包含导入的模块对象的列表。

答案 1 :(得分:0)

严格地说,如果没有以某种方式调用代码,我就无法运行代码。为此,正在运行的程序可以使用

import importlib

这样,一旦找到该文件,您就可以将其导入:

mod = importlib.import_module(import_name, pkg_name)

如果该文件提供已知函数(在本例中为Run),则可以使用:

调用它
mod.Run(your_args)

这适用于Python 2.7。版本3可能不同。