在Python库中动态加载模块的最佳方法

时间:2013-05-16 20:51:11

标签: python plugins

编辑:结果问题与路径有关。

如果我进入包含该库的目录并运行python __init__.py,那么导入工作正常。如果我在不同的目录中并尝试导入库本身(即在父目录中,并尝试导入),则会发生故障。

我没有看到任何方法为字面指定import语句的路径。

所以,我想知道最好的方法是将scriptDir中的目录添加到sys.path中吗?这是最好的方法吗?我觉得应该有更优雅的方法,但是......


我想写一个我能够轻松扩展的库。

这是我想要做的一些骨架/伪代码。实际上这个代码要复杂得多,但它遵循基本前提 - 导入每个文件,检查它,并确定是否应该使用它;然后将其分配到模块引用列表中。所有这些都将包含在一个库文件夹中。

我希望该库在导入时动态导入在其目录中找到的以“plugin_”开头的文件。见代码:

初始化的.py:

import os.path

scriptDir = os.path.dirname(__file__)
mods = []
thisMod = 0

for file in os.listdir(scriptDir):
    if (file[0:7] == "plugin_" and file[-3:] == ".py"):
        thisMod = __import__(".".join(file.split(".")[0:-1]))
        print "debug: imported %s" % thisMod.modName
        if (thisMod.enable == True):
            mods.append(thisMod)
        else:
            print "debug: not loading %s because it's disabled." % thisMod.modName

def listMods():
    "This function should print the names of all loaded modules."
    for m in mods:
        print "debug: module %s" % m.modName

def runMods():
    "This function should execute the run method for ALL modules."
    for m in mods:
        c = m.ModuleClass()
        c.run()

def selectMod(modNum):
    "This function should let us select a single module for the runSelectedMod function."
    thisMod = mods[modNum]

def runSelectedMod():
    "This function should run the 'run' method for ONLY the previously selected module."
    if (thisMod == 0):
        raise ArgumentError("you didn't assign a module yet.")
    c = thisMod.ModuleClass()
    c.run()

plugin_test1.py

modName = "test module 1"
enable = True
class ModuleClass:
    def run(self):
        print "test module 1 is running"

plugin_math.py

modName = "math module"
enable = True
class ModuleClass:
    def run(self):
        print "mathematical result: %d" % (1+1)

plugin_bad.py

modName = "bad module"
enable = False
class ModuleClass:
    def __init__(self):
        print "x"[4] # throws IndexError, this code should not run.
    def run(self):
        print "divide by zero: %f" % (5 / 0) # this code should not run.

我已经发现的问题是 import 不起作用,因为我没有导入整个库,而是导入单个文件。我猜是为了这个目的,有导入的替代语法?例如,import plugin_testfrom plugin_math import ModuleClass可以使用,但我对 import 的使用不是。我收到一个错误:

thisMod = __import__(".".join(file.split(".")[0:-1]))
ImportError: No module named plugin_test1

现在,另一个问题是:如果我使用py2exe,py2app等将其编译成一个紧凑的库,这将如何最终起作用?如果我记得,请不要将这些应用程序压缩到site_packages.zip文件中?...

我还在学习如何在Python中使用这种类型的高级编码,所以任何建议都值得赞赏。

谢谢!

1 个答案:

答案 0 :(得分:0)

我能够在Python 3中运行它。唯一不涉及语法的变化是scriptDir

import os.path

scriptDir = os.path.dirname(os.path.abspath(__file__))
mods = []
thisMod = 0

for file in os.listdir(scriptDir):
    if (file[0:7] == "plugin_" and file[-3:] == ".py"):
        thisMod = __import__(".".join(file.split(".")[0:-1]))
        print ("debug: imported %s" % thisMod.modName)
        if (thisMod.enable == True):
            mods.append(thisMod)
        else:
            print ("debug: not loading %s because it's disabled." % thisMod.modName)

def listMods():
    "This function should print the names of all loaded modules."
    for m in mods:
        print ("debug: module %s" % m.modName)

def runMods():
    "This function should execute the run method for ALL modules."
    for m in mods:
        c = m.ModuleClass()
        c.run()

def selectMod(modNum):
    "This function should let us select a single module for the runSelectedMod function."
    thisMod = mods[modNum]

def runSelectedMod():
    "This function should run the 'run' method for ONLY the previously selected module."
    if (thisMod == 0):
        raise ArgumentError("you didn't assign a module yet.")
    c = thisMod.ModuleClass()
    c.run()

给出:

C:\Users\mm\Desktop\ING.SW\python>python so\dina.py
debug: imported bad module
debug: not loading bad module because it's disabled.
debug: imported math module
debug: imported test module 1

我猜你有一个不同的问题,因为实际上是读取了文件名(因为它打印在错误信息中),但仍然......