如何以字符串形式动态导入模块?

2024-11-21 08:33:00
admin
原创
155
摘要:问题描述:我正在编写一个以命令作为参数的 Python 应用程序,例如:$ python myapp.py command1 我希望应用程序具有可扩展性,也就是说,能够添加实现新命令的新模块,而无需更改主应用程序源。树看起来像这样:myapp/ __init__.py commands/ ...

问题描述:

我正在编写一个以命令作为参数的 Python 应用程序,例如:

$ python myapp.py command1

我希望应用程序具有可扩展性,也就是说,能够添加实现新命令的新模块,而无需更改主应用程序源。树看起来像这样:

myapp/
    __init__.py
    commands/
        __init__.py
        command1.py
        command2.py
    foo.py
    bar.py

所以我希望应用程序在运行时找到可用的命令模块并执行适当的模块。

Python 定义了一个__import__()函数,它以字符串作为模块名称:

__import__(name, globals=None, locals=None, fromlist=(), level=0)

函数导入模块name,可能使用给定的globalslocals来确定如何在包上下文中解释名称。 给出fromlist应从 给出的模块导入的对象或子模块的名称name

来源:https://docs.python.org/3/library/functions.html#__import_ _

所以目前我有类似的东西:

command = sys.argv[1]
try:
    command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
    # Display error message

command_module.run()

这工作得很好,我只是想知道是否有可能有一种更惯用的方法来完成我们用这段代码所做的事情。

请注意,我特别不想使用eggs或扩展点。这不是一个开源项目,我也不指望有“插件”。重点是简化主应用程序代码,并消除每次添加新命令模块时修改它的需要。


另请参阅: 如何根据完整路径动态导入模块?


解决方案 1:

对于 Python 2.7 和 3.1 及更高版本,推荐的方法是使用importlib模块:

importlib.import_module(name, package=None)

导入模块。name 参数指定要导入的模块,以绝对或相对形式(例如,pkg.mod..mod)导入。如果以相对形式指定名称,则必须将 package 参数设置为将充当解析包名称的锚点的包的名称(例如,import_module('..mod', 'pkg.subpkg')将导入pkg.mod)。

例如

my_module = importlib.import_module('os.path')

解决方案 2:

对于 Python 2.7/3.1 之前的版本,基本上就是这样做的。

对于较新的版本,请参阅importlib.import_modulePython 2和Python 3。

或者__import__您可以通过以下步骤导入模块列表:

>>> moduleNames = ['sys', 'os', 're', 'unittest'] 
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)

直接摘自《深入 Python》。

解决方案 3:

注意:自 Python 3.4 起, imp已被弃用,取而代之的是importlib

如上所述,imp模块为您提供了加载功能:

imp.load_source(name, path)
imp.load_compiled(name, path)

我以前曾使用过它们来执行类似的事情。

在我的例子中,我定义了一个特定的类,其中包含所需的定义方法。加载模块后,我会检查该类是否在模块中,然后创建该类的一个实例,如下所示:

import imp
import os

def load_from_file(filepath):
    class_inst = None
    expected_class = 'MyClass'

    mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1])

    if file_ext.lower() == '.py':
        py_mod = imp.load_source(mod_name, filepath)

    elif file_ext.lower() == '.pyc':
        py_mod = imp.load_compiled(mod_name, filepath)

    if hasattr(py_mod, expected_class):
        class_inst = getattr(py_mod, expected_class)()

    return class_inst

解决方案 4:

使用importlib

导入源文件

以下是文档中稍加改编的示例:

import sys
import importlib.util

file_path = 'pluginX.py'
module_name = 'pluginX'

spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)

# Verify contents of the module:
print(dir(module))

从这里开始,module将是一个代表模块的模块对象(与通过执行pluginX分配的相同)。因此,要调用中定义的函数(没有参数),请使用。pluginX`import pluginXhellopluginX`module.hello()

为了获得“导入”模块功能的效果from,请将其存储在已加载模块的内存缓存中,然后执行相应的from导入:

sys.modules[module_name] = module

from pluginX import hello
hello()

导入包

要导入包,只需调用即可。假设当前工作目录中import_module有一个包文件夹;那么只需执行pluginX

import importlib

pkg = importlib.import_module('pluginX')

# check if it's all there..
print(dir(pkg))

解决方案 5:

使用imp 模块,或者更直接的__import__()函数。

解决方案 6:

如果你想在本地使用它:

>>> mod = 'sys'
>>> locals()['my_module'] = __import__(mod)
>>> my_module.version
'2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)]'

相同globals()

解决方案 7:

您可以使用exec

exec("import myapp.commands.%s" % command)

解决方案 8:

与@monkut 的解决方案类似,但可重复使用且具有容错功能,详情请见此处http://stamat.wordpress.com/dynamic-module-import-in-python/

import os
import imp

def importFromURI(uri, absl):
    mod = None
    if not absl:
        uri = os.path.normpath(os.path.join(os.path.dirname(__file__), uri))
    path, fname = os.path.split(uri)
    mname, ext = os.path.splitext(fname)

    if os.path.exists(os.path.join(path,mname)+'.pyc'):
        try:
            return imp.load_compiled(mname, uri)
        except:
            pass
    if os.path.exists(os.path.join(path,mname)+'.py'):
        try:
            return imp.load_source(mname, uri)
        except:
            pass

    return mod

解决方案 9:

下面的部分对我有用:

>>>import imp; 
>>>fp, pathname, description = imp.find_module("/home/test_module"); 
>>>test_module = imp.load_module("test_module", fp, pathname, description);
>>>print test_module.print_hello();

如果你想在 shell 脚本中导入:

python -c '<above entire code in one line>'

解决方案 10:

以下对我有用:

import sys, glob
sys.path.append('/home/marc/python/importtest/modus')
fl = glob.glob('modus/*.py')
modulist = []
adapters=[]
for i in range(len(fl)):
    fl[i] = fl[i].split('/')[1]
    fl[i] = fl[i][0:(len(fl[i])-3)]
    modulist.append(getattr(__import__(fl[i]),fl[i]))
    adapters.append(modulist[i]())

它从文件夹“modus”加载模块。模块有一个与模块名称同名的类。例如,文件 modus/modu1.py 包含:

class modu1():
    def __init__(self):
        self.x=1
        print self.x

结果是动态加载的类“适配器”的列表。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用