Telling __import__ where to look - am I stuck with sys.path?
I have a project in pure Python with a rudimentary plugin system: you write a module that defines a class with a specific interface and name, and the program imports the module and subsequently instantiates the class as needed.
Currently, the plugins all come from a specific folder (subdirectory of where the main .py file is located). I would like to be able to have them elsewhere on disk, and instruct the program to look for plugins in a specific place. Can I do this, for one-off dynamic imports, in a cleaner way than modifying sys.path
? I don't want to pollute this global.
Related: can I count on sys.path[0]
being the path to the script, even if that differs from the current worki开发者_开发问答ng directory (os.getcwd()
)?
EDIT: I forgot to mention - I want to be able to get plugins from several different folders, with the user specifying paths to plugin folders. Currently, each of these folders is set up as a package (with an __init__.py
); I can trivially scrap this if it causes a problem.
This might seem weird, but you can modify a module's __path__
variable and then import from it. Then you're not messing with the global import space in sys.path.
Edit: If the directories are loaded at run time, then you don't need a plugins.py file to store them. You can create the module dynamically:
main.py:
#create the plugins module (pseudo-package)
import sys, os
sys.modules['plugins'] = plugins = type(sys)('plugins')
plugins.__path__ = []
for plugin_dir in ['plugins1', 'plugins2']:
path = os.path.join(sys.path[0], 'addons', plugin_dir)
plugins.__path__.append(path)
After creating the dynamic module, you can load the plugins as before, using either import_module
or __import__
:
from importlib import import_module
myplugins = []
for plugin in ['myplugin1', 'myplugin2']:
myplugins.append(import_module('plugins.' + plugin))
myplugins[-1].init()
##or using __import__:
myplugins = []
for plugin in ['myplugin1', 'myplugin2']:
myplugins.append(getattr(__import__('plugins.' + plugin), plugin))
myplugins[-1].init()
addons/plugins1/myplugin1.py:
def init():
print('myplugin1')
addons/plugins2/myplugin2.py:
def init():
print('myplugin2')
I've never used this, but it does work in both Python 2 & 3.
精彩评论