导入没有.py扩展名的python模块

com*_*pie 61 python import

我有一个名为foobar的文件(没有.py扩展名).在同一目录中,我有另一个试图导入它的python文件:

import foobar
Run Code Online (Sandbox Code Playgroud)

但这只有在我将文件重命名为foobar.py时才有效.是否可以导入没有.py扩展名的python模块?

更新:该文件没有扩展名,因为我也将它用作独立脚本,我不想输入.py扩展名来运行它.

Update2:我将选择下面提到的符号链接解决方案.

Eli*_*sky 41

您可以使用该imp.load_source功能(来自imp模块)从给定的文件系统路径动态加载模块.

foobar = imp.load_source('foobar', '/path/to/foobar')
Run Code Online (Sandbox Code Playgroud)

这个SO讨论也展示了一些有趣的选择.

  • 自3.4以来,这已被弃用.知道如何从3.4+中没有.py扩展名的文件导入? (3认同)
  • 如果在返回值中赋值,第一个参数''foobar'的用法是什么? (2认同)
  • @AnmolSinghJaggi它设置模块`__name__`属性; 通常这是由文件名确定的,但由于您使用的是非标准文件名(根本不包含任何有效的python标识符),您必须指定模块名称.存储对创建的模块对象的引用的变量名称是无关紧要的,就像你将`foo.bar导入为baz`一样,变量`baz`引用的模块仍将具有其原始的`__name__`. (2认同)
  • 对于Python 3.4+:此答案更为准确:/sf/ask/182073321/#43602645 (2认同)

小智 15

像其他人提到的那样,您可以使用imp.load_source,但它会使您的代码更难以阅读.如果您需要导入直到运行时才知道其名称或路径的模块,我真的只会推荐它.

你不想使用.py扩展名的原因是什么?不想使用.py扩展名的最常见情况是因为python脚本也作为可执行文件运行,但您仍然希望其他模块能够导入它.如果是这种情况,将功能移动到具有类似名称的.py文件中可能是有益的,然后将其foobar用作包装器.

  • 或者代替包装,只需将符号链接foobar.py添加到foobar(假设您不在Windows上) (14认同)

Mad*_*ist 14

这是Python 3.4+的解决方案:

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("foobar", SourceFileLoader("foobar", "/path/to/foobar"))
foobar = module_from_spec(spec)
spec.loader.exec_module(foobar)
Run Code Online (Sandbox Code Playgroud)

使用spec_from_loader和显式指定SourceFileLoader将强制机器将文件作为源加载,而不试图从扩展中找出文件的类型.这意味着您可以加载文件,即使它没有列出importlib.machinery.SOURCE_SUFFIXES.

如果要在第一次加载后按名称继续导入文件,请将模块添加到sys.modules:

sys.modules['foobar'] = foobar
Run Code Online (Sandbox Code Playgroud)

  • 这个模块拼命需要一个foobar = importlib.nice_import('foobar')`帮助器。 (2认同)

Dan*_*olo 13

imp.load_source(module_name, path)应该这样做,或者你可以做更详细的imp.load_module(module_name, file_handle, ...)路线,如果你有一个文件句柄


Cir*_*四事件 8

importlib 辅助功能

这是一个方便的、随时可用的帮助程序来替换imp,例如,基于以下提到的内容:https : //stackoverflow.com/a/43602645/895245

主文件

#!/usr/bin/env python3

import os
import importlib
import sys

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)
Run Code Online (Sandbox Code Playgroud)

非主要

x = 1
Run Code Online (Sandbox Code Playgroud)

跑:

python3 main.py
Run Code Online (Sandbox Code Playgroud)

输出:

<module 'not_main' from 'not-main'>
1
Run Code Online (Sandbox Code Playgroud)

我替换-_因为我没有扩展名的可导入 Python 可执行文件有连字符。这不是强制性的,但会产生更好的模块名称。

这种模式也在文档中提到:https : //docs.python.org/3.7/library/importlib.html#importing-a-source-file-directly

我最终转向它,因为在更新到 Python 3.7 后,import imp打印:

DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
Run Code Online (Sandbox Code Playgroud)

我不知道如何关闭它,这是在以下位置询问的:

在 Python 3.7.3 中测试。