【问题标题】:Python 3.4: How to import a module given the full path? [duplicate]Python 3.4:如何在给定完整路径的情况下导入模块? [复制]
【发布时间】:2014-12-09 14:25:59
【问题描述】:

如何在 Python 3.4 中根据完整路径加载 Python 模块?

一个类似的问题How to import a module given the full path? 涵盖了 3.4 之前的 Python 版本,但结论是 Python 3.4 中的支持已被弃用,因此不推荐使用 Python 3.4 的任何解决方案。

请注意,此问题与Import abitrary python source file. (Python 3.3+) 不重复,因为此问题的答案也使用loader.load_module(),如answer 中所述,loader.load_module() 在 Python 3.4 中已弃用,详细信息在 Consider leaving importlib.abc.Loader.load_module() 中,文档在 @ 987654325@.

因此需要在 Python 3.4 中支持通过完整路径导入模块的解决方案。

【问题讨论】:

标签: python python-3.x


【解决方案1】:

这应该适用于所有 python 文件,无论文件扩展名如何:

import importlib.machinery

modulename = importlib.machinery.SourceFileLoader('modulename','/Path/To/module.py').load_module()

imp.load_moduledocumentation 的弃用消息中提到了此方法。

【讨论】:

  • 感谢您指出这一点,它在当前的 Python 3.4 中看起来完全受支持,因此必须是替代品,因此答案是 :-)
  • 仅供参考:自 3.6 版起已弃用:改用 importlib.abc.Loader.exec_module()。 Source
  • importlib.machinery.ExtensionFileLoader 似乎适用于 C/C++ 扩展模块。
【解决方案2】:

根据3.6 docs 支持和不推荐使用的方法是这样的:

def import_file(full_name, path):
    """Import a python module from a path. 3.4+ only.

    Does not call sys.modules[full_name] = path
    """
    from importlib import util

    spec = util.spec_from_file_location(full_name, path)
    mod = util.module_from_spec(spec)

    spec.loader.exec_module(mod)
    return mod

【讨论】:

  • module_from_spec 仅在 Python 3.5 及更高版本中可用。
【解决方案3】:

已经给出的答案有效,但不必要地笨拙。更简单的方法:

import sys, os, importlib

sys.path.append(os.path.dirname(filename))
mname = os.path.splitext(os.path.basename(filename))[0]
imported = importlib.import_module(mname)                       
sys.path.pop()

imported 是导入的模块;您可以通过imported.method(arg) 正常使用它。最后一行不是绝对必要的,但不要在sys.path 中留下不必要的条目会更干净(特别是如果您要多次运行代码)。这在 3.4 中有效,并且不使用任何标记为已弃用的内容。

【讨论】:

  • 如果 mname 是 "/my/own/dir/stat.py" 那么代码它将导入 Python 标准库模块 stat,而不是指定的模块,由于意外名称与 Python 标准库中的模块冲突。所以这并不适用于所有情况。
  • 是的。我认为,但不确定,这可以通过执行sys.path.insert(0, os.path.dirname(filename)) 而不是.append() 来解决(当然,之后执行.pop(0))。取决于sys.path 是否具有标准搜索路径语义。当然,如果你这样做了,那么之后删除条目就更重要了,以防止该目录中的文件隐藏标准库。 (在更基础的层面上,将模块命名为与标准库模块相同可能是个坏主意。但是。)
  • 是的,将它放在搜索列表的首位可能会有所帮助,但其他模块恰好以标准库命名,然后可能会影响标准库。同意您应该避免使用现有的标准库模块名称。但是,我认为所有这些变通方法的考虑都是缺少一种将文件作为模块导入的简单方法的症状......就像以前版本的 Python 一样。
  • 小心使用 sys.path.pop() 或 sys.path.pop(0)。您假设 sys.path 没有被您的目标导入模块修改。然后谨慎行事 sys.remove(os.path.dirname(filename)) 代替。
【解决方案4】:

以下函数适用于 Python 3.4 - 它用于加载和运行模块中的特定函数,但您需要将文件夹添加到 sys 路径。

sys.path.append("path_to_your_file_to_import")
tool = {'file':'test_tool.py', 
    'function':'sum_even_numbers', 
    'args':['list'], 
    'return':['int']
}

args = [1,2,3]

def run(tool, args, silent='Y'):
        if silent == 'N':
            print('main called ' + tool['file'] + '->' + tool['function'] + ' with ', args, ' = ', tool['return'])
        mod = __import__( os.path.basename(tool['file']).split('.')[0])
        func = getattr(mod, tool['function'])
        tool['return'] = func(args)
        return tool['return']

通过调用它

run(tool, args)

【讨论】:

  • 这只是简单的基于名称的import,如语句import test_tool,而不是在给定位置(路径)导入模块。此外,self 部分使它看起来像是从一个类中复制粘贴,因此对run(tool, args) 的普通调用将导致语法错误。
  • @EquipDev 你是对的 - 需要将文件夹添加到 sys 路径。我已经编辑以显示这一点,并且还删除了 self 参数。它来自我正在学习的课程 - github.com/acutesoftware/AIKIF/blob/master/aikif/tools.py
  • 使用sys.path 的常规导入 (import) 机制不会让您导入文件名为“sys.py”的模块,因为这会与内置-in sys 模块。
  • 那么您究竟希望能够导入什么 - 这些是标准的 Python 模块,还是您希望能够从任何可定义的路径运行代码?一种方法是将文件从其路径复制到已知的本地路径,使用 GUID 重命名并导入。
  • 只想根据文件路径将文件作为模块导入。它不应该是火箭科学。在 Python 3.3 之前很容易,在 Python 3.3 中可能,但在 3.4 中我不知道如何以受支持的方式来做。
猜你喜欢
  • 2021-10-04
  • 2022-11-30
  • 2019-10-31
  • 2017-06-11
  • 1970-01-01
相关资源
最近更新 更多