导入任意python源文件。(Python 3.3+;)

导入任意python源文件。(Python 3.3+;),python,python-3.x,python-3.3,Python,Python 3.x,Python 3.3,如何在python 3.3+中导入任意python源文件(其文件名可以包含任何字符,并且不总是以.py结尾) 我使用的方法如下: >>> import imp >>> path = '/tmp/a-b.txt' >>> with open(path, 'U') as f: ... mod = imp.load_module('a_b', f, path, ('.py', 'U', imp.PY_SOURCE)) ... >>

如何在python 3.3+中导入任意python源文件(其文件名可以包含任何字符,并且不总是以
.py
结尾)

我使用的方法如下:

>>> import imp
>>> path = '/tmp/a-b.txt'
>>> with open(path, 'U') as f:
...     mod = imp.load_module('a_b', f, path, ('.py', 'U', imp.PY_SOURCE))
...
>>> mod
<module 'a_b' from '/tmp/a-b.txt'>
导入imp >>>路径='/tmp/a-b.txt' >>>打开(路径“U”)作为f: ... mod=imp.load_模块('a_b',f,path,('.py',U',imp.py_源)) ... >>>国防部 它仍然在Python 3.3中工作,但根据
imp.load_module
文档,它已被弃用:

自3.3版以来已弃用:不需要加载程序,因为应使用加载程序 不推荐使用load module and find_module()

imp
模块文档建议使用
importlib

注意新程序应使用importlib而不是此模块

在python 3.3+中加载任意python源文件而不使用不推荐的
imp.load\u模块
函数的正确方法是什么?

从中找到了一个解决方案

使用:


>>进口进口机械
>>>导入importlib.util
>>>loader=importlib.machine.SourceFileLoader('a_b','/tmp/a-b.txt'))
>>>spec=importlib.util.spec_from_loader(loader.name,loader)
>>>mod=importlib.util.module\u from\u spec(spec)
>>>加载程序执行模块(mod)
>>>国防部

@falsetru解决方案的较短版本:

>>> import importlib.util
>>> spec = importlib.util.spec_from_file_location('a_b', '/tmp/a-b.py')
>>> mod = importlib.util.module_from_spec(spec)
>>> spec.loader.exec_module(mod)
>>> mod
<module 'a_b' from '/tmp/a-b.txt'>
导入importlib.util >>>spec=importlib.util.spec_from_file_location('a_b','/tmp/a-b.py')) >>>mod=importlib.util.module\u from\u spec(spec) >>>规格加载程序执行模块(mod) >>>国防部 我用Python3.5和3.6测试了它


根据评论,它不适用于任意文件扩展名。

类似于@falsetru,但适用于Python 3.5+,并说明使用
importlib.util.module\u from_spec
而非
types.ModuleType时的状态:

此函数[
importlib.util.module\u from_spec
]优于使用
types.ModuleType
创建新的 模块as spec用于在上设置尽可能多的导入控制属性 尽可能地使用该模块

通过修改
importlib.machine.SOURCE\u后缀
列表,我们可以单独导入带有
importlib
的任何文件

导入导入库
importlib.machine.SOURCE_后缀.append(“”)#空字符串以允许任何文件
spec=importlib.util.spec\u from\u file\u位置(模块名称、文件路径)
module=importlib.util.module\u from_spec(spec)
规格加载器执行模块(模块)
#如果需要:importlib.machine.SOURCE_后缀.pop()

importlib
helper函数

下面是一个方便的、随时可用的帮助程序,可以用一个示例替换
imp
。技术与的相同,这只是提供了一个更方便的功能

main.py

#!/usr/bin/env python3

import os
import importlib

def import_path(path):
    module_name = os.path.basename(path).replace('-', '_')
    spec = importlib.util.spec_from_loader(
        module_name,
        importlib.machinery.SourceFileLoader(module_name, path)
    )
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    sys.modules[module_name] = module
    return module

notmain = import_path('not-main')
print(notmain)
print(notmain.x)
非主要

x = 1
运行:

输出:

<module 'not_main' from 'not-main'>
1
我不知道如何关闭它,有人问:


在Python 3.7.3中测试。

Downvoter:如何改进答案?如果你有更好的方法来完成我想要的,请让我知道。有一个有用的警告,
load\u module
通过
warnings忽略。catch\u warnings
。如果改用
mod=imp.load_source('a_b','/tmp/a-b.txt')
,则会引发以下警告(使用
-Wall
):
弃用警告:imp.load_source()已弃用;使用importlib.machine.SourceFileLoader(name,pathname).load_module()代替
@eryksun,没错。谢谢你的评论。顺便说一句,Python3.4(rc1)没有显示与Python3.3.x不同的替代用法。@iHavenoidia,请发布一个单独的问题,以便其他人可以回答您,其他用户也可以阅读答案。@falsetru事实上,我没有答案,到目前为止。我在这里发表评论是因为我在发表我的问题后偶然发现了你的答案。如果你知道怎么做,我会很感激的!我能问一下你为什么要这样做吗?我是importlib的维护者,我一直在试图从人们那里得到答案,他们为什么在直接的导入语句上使用
imp.load\u module()
。您是否希望稍后按名称导入模块(例如,
import a_b
)?您是否介意在这种方法中不使用任何自定义进口商?您是否希望该模块功能齐全(例如定义
\uuuuu name\uuuuuu
\uuuuuu loader\uuuuu
)?@BrettCannon是一个第三方程序,它定期(每小时一次)修改包含python语句的文本文件(主要是
这类行的
)。文件名不以
.py
结尾。我的程序读取了那个文件。@BrettCannon,我不知道自定义导入程序。我不在乎模块是全功能的。IOW使用Python作为一种非常简单的数据结构格式。谢谢你的信息@BrettCannon——我刚刚遇到一个例子,我需要从一个名为版本号的目录(例如,“v1.0.2”)中导入一些Python代码。虽然可能,但重命名目录是非常不可取的。我最后使用了下面stefan scherfke的解决方案。
importlib.util.spec\u from\u file\u location(..)
为我返回
None
;导致以下调用中的importlib.util.module出现异常。(请参阅)
importlib.util.spec\u from_file_location
适用于已知的文件扩展名(
.py
.so
,…),但不适用于其他文件(
.txt
)。哦,我只在Python文件中使用它,但修改了我的示例,使其看起来像上面的示例,并没有对其进行测试…我更新了它。很有趣,虽然这种将空字符串附加到源后缀列表的方法对于导入重命名的Python源模块非常有效,但是导入重命名的扩展模块的等效方法却不起作用。。。也就是说,使用
importlib.machine.EXTENSION\u后缀.append(“”)
仍然使
importlib.util.spec\u从\u文件\u位置
retu
#!/usr/bin/env python3

import os
import importlib

def import_path(path):
    module_name = os.path.basename(path).replace('-', '_')
    spec = importlib.util.spec_from_loader(
        module_name,
        importlib.machinery.SourceFileLoader(module_name, path)
    )
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    sys.modules[module_name] = module
    return module

notmain = import_path('not-main')
print(notmain)
print(notmain.x)
x = 1
python3 main.py
<module 'not_main' from 'not-main'>
1
DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses