导入不带.py扩展名的python模块

导入不带.py扩展名的python模块,python,import,Python,Import,我有一个名为foobar的文件(没有.py扩展名)。在同一目录中,我有另一个python文件试图导入它: import foobar 但是,只有将文件重命名为foobar.py时,这才有效。是否可以导入没有.py扩展名的python模块 更新:该文件没有扩展名,因为我也将其用作独立脚本,并且我不想键入.py扩展名来运行它 更新2:我将使用下面提到的符号链接解决方案。您可以使用imp.load\u source函数(从imp模块)从给定的文件系统路径动态加载模块 import imp fooba

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

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

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


更新2:我将使用下面提到的符号链接解决方案。

您可以使用
imp.load\u source
函数(从
imp
模块)从给定的文件系统路径动态加载模块

import imp
foobar = imp.load_source('foobar', '/path/to/foobar')

这还显示了一些有趣的选项。

imp.load\u源代码(模块名称、路径)
应该做,或者您可以做更详细的
imp.load\u模块(模块名称、文件句柄等)
路由如果您有一个文件句柄,而不是像其他人提到的那样,您可以使用imp.load\u源代码,但这会使您的代码更难阅读。只有当您需要导入在运行时之前名称或路径未知的模块时,我才真正推荐它


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

如果使用软件包管理器(deb或类似工具)安装脚本,另一个选项是使用setuptools:

“…要使脚本的文件名与Windows和POSIX平台上的本地约定相匹配并不容易。另一方面,当实际的“主”脚本是某个模块中的函数…setuptools通过自动为您生成具有正确扩展名的脚本修复了所有这些问题,在Windows上它甚至会创建一个.exe文件


以下是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)
使用并显式指定将强制将文件作为源加载,而不尝试从扩展名中找出文件的类型。这意味着您可以加载该文件,即使该文件未在中列出

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

sys.modules['foobar'] = foobar

importlib
helper函数

下面是一个方便的、随时可用的帮助程序,用于替换
imp
,并提供了一个示例,该示例基于以下内容:

main.py

#!/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)
非主要

x = 1
运行:

输出:

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


在Python 3.7.3中进行了测试。

我尝试了上面的所有建议,但对于一个非常简单的情况,我无法找到解决方案,即我要对没有
.py
扩展名的cli脚本进行pytest

为什么
spec.loader.exec_module()
会在“
”上引发IsADirectoryError

我在一个目录中有两个文件:

%
ls

cli_with_no_dot_py      test_cli_with_no_dot_py.py
%
cat cli\u,不带点\u py

#!/usr/bin/env python3

cool_thing = True
print("cool_thing is", cool_thing)
cool_thing is True
%
/cli\u带\u no\u dot\u py

#!/usr/bin/env python3

cool_thing = True
print("cool_thing is", cool_thing)
cool_thing is True
%
cat test\u cli\u带\u no\u dot\u py.py

#!/usr/bin/env python3

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
spec = spec_from_loader("cli_with_no_dot_py",
    SourceFileLoader("cli_with_no_dot_py", "."))
print("spec:", spec)
cli_with_no_dot_py = module_from_spec(spec)
print("cli_with_no_dot_py):", cli_with_no_dot_py)
print("dir(cli_with_no_dot_py:", dir(cli_with_no_dot_py))
print("spec.loader:", spec.loader)
spec.loader.exec_module(cli_with_no_dot_py)  # !!! IsADirectoryError !!!

def test_cool_thing():
    print("cli_with_no_dot_py.cool_thing is", cli_with_no_dot_py.cool_thing)
    assert cli_with_no_dot_py.cool_thing
%
pytest

======================================================================== test session starts ========================================================================
platform darwin -- Python 3.8.2, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /Users/cclauss/Python/pytest_a_cli_tool
collected 0 items / 1 error

============================================================================== ERRORS ===============================================================================
____________________________________________________________ ERROR collecting test_cli_with_no_dot_py.py ____________________________________________________________
test_cli_with_no_dot_py.py:11: in <module>
    spec.loader.exec_module(cli_with_no_dot_py)
<frozen importlib._bootstrap_external>:779: in exec_module
    ???
<frozen importlib._bootstrap_external>:915: in get_code
    ???
<frozen importlib._bootstrap_external>:972: in get_data
    ???
E   IsADirectoryError: [Errno 21] Is a directory: '.'
-------------------------------------------------------------------------- Captured stdout --------------------------------------------------------------------------
spec: ModuleSpec(name='cli_with_no_dot_py', loader=<_frozen_importlib_external.SourceFileLoader object at 0x10e106f70>, origin='.')
cli_with_no_dot_py: <module 'cli_with_no_dot_py' from '.'>
dir(cli_with_no_dot_py): ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
spec.loader: <_frozen_importlib_external.SourceFileLoader object at 0x10e106f70>
====================================================================== short test summary info ======================================================================
ERROR test_cli_with_no_dot_py.py - IsADirectoryError: [Errno 21] Is a directory: '.'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
========================================================================= 1 error in 0.09s ==========================================================================
==========================================================================================================================================测试会话开始========================================================================
平台darwin——Python 3.8.2、pytest-5.4.1、py-1.8.1、Plugy-0.13.1
rootdir:/Users/cclauss/Python/pytest\u a\u cli\u工具
已收集0个项目/1个错误
==============================================================================================================================错误===============================================================================
____________________________________________________________使用\u no\u dot\u py.py收集测试\u cli\u时出错____________________________________________________________
测试带有点的客户端。点:11:in
spec.loader.exec_模块(cli_,不带点)
:779:in exec_模块
???
:915:输入get_代码
???
:972:输入获取数据
???
E isDirectoryError:[Errno 21]是一个目录:'
--------------------------------------------------------------------------俘获stdout--------------------------------------------------------------------------
规格:ModuleSpec(name='cli',带有'u no'u dot'u py',loader=,origin='。)
不带点的客户端:
目录(不带点的cli):[“文档”、“文件”、“加载程序”、“名称”、“包”、“规范”]
规格装载机:
======================================================================================================================================================简短测试摘要信息======================================================================
错误测试\u cli\u带有\u no\u dot\u py.py-isDirectoryError:[Errno 21]是一个目录:'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 中断:收集过程中出现1个错误!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
===============================================================================================================================0.09s内出现1个错误==========================================================================

我很感兴趣。为什么python文件没有扩展名
py
呢?有时候,将python用于配置文件(扩展名为.conf)或表示一种特殊类型的文件是不错的选择。在我的例子中,这对管理员来说更方便。我有一个配置为python文件和bash脚本的文件。我给了它一个
pysh
扩展…如果这是与配置相关的东西,我建议使用
ConfigParser
@voyager的一个原因是python脚本带有.cgi扩展名而不是.py扩展名,或者不用包装,只需将foobar.py符号链接到foobar(假设您不在Windows上)@whaley,是的,这会更干净。你可以使用.bat for windows来完成同样的事情。我有一个