导入错误:没有名为package的模块。

11

我觉得在Python中导入模块很复杂,所以我正在进行实验以澄清这一点。这是我的文件结构:

PythonTest/
  package/
    __init__.py
    test.py

__init__.py 的内容:

package = 'Variable package in __init__.py'
from package import test

test.py的内容:

from package import package
print package

当我在PythonTest目录之外,并执行python package/test.py命令时,我会得到以下输出:

Traceback (most recent call last):
  File "package/test.py", line 1, in <module>
    from package import package
ImportError: No module named package

期望的输出是__init__.py中的variable package。我错在哪里了?


然而,在交互模式下,我可以得到期望的输出:

sunqingyaos-MacBook-Air:PythonTest sunqingyao$ python
Python 2.7.10 (default, Oct 23 2015, 19:19:21) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import package
Package in __init__.py

似乎没有为“package”包设置模块搜索路径,以便它可以被找到。 - user2357112
@user2357112 那我应该设置 PYTHONPATH 还是修改 sys.path 呢?但为什么在交互模式下一切都正常呢? - nalzok
我假设您正在与文件相同的目录中启动交互模式,因此该路径会自动成为搜索路径的一部分。请尝试从完全不同的目录启动Python。 - WombatPM
我调用交互模式的目录正是我执行python package/test.py的目录。当我进入一个完全不同的目录时,这两种方法都不起作用。 - nalzok
1
python package/test.py 会将执行脚本的目录添加到搜索路径中,而不是启动脚本的目录。 - user2357112
@user2357112 那么为了解决这个问题,我应该在 PythonTest 中编写另一个模块,并从中调用 test.py 吗?(也许直接调用包中的模块而不经过其包是一个错误?) - nalzok
1个回答

13

首先,让我们看看Python如何搜索包和模块。sys.path

一个字符串列表,指定模块的搜索路径。从环境变量PYTHONPATH进行初始化,加上一个安装相关的默认路径。

这就是搜索路径。因此,如果您的模块/包位于sys.path中的任意一个位置,python解释器都能够找到并导入它。文档中还有更多内容:

在程序启动时初始化时,该列表的第一项 path [0] 是包含用于调用Python解释器的脚本的目录。 如果脚本目录不可用(例如,如果交互式调用解释器或者从标准输入读取脚本),则 path [0] 为空字符串,这将指示Python首先在当前目录中搜索模块。

我以test.py为例进行了修改。

import sys; import pprint
pprint.pprint(sys.path)

from package import package
print package 

有两种情况:

$ python package/test.py
['/Users/laike9m/Dev/Python/TestPython/package',
 '/usr/local/lib/python2.7/site-packages/doc2dash-2.1.0.dev0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/zope.interface-4.1.3-py2.7-macosx-10.10-x86_64.egg',
 '/usr/local/lib/python2.7/site-packages/six-1.10.0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/colorama-0.3.3-py2.7.egg',

你看到的是,path[0]/Users/laike9m/Dev/Python/TestPython/package,这是包含脚本test.py的目录,该脚本被用于调用Python解释器。

$ python                                         
Python 2.7.12 (default, Jun 29 2016, 14:05:02)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import package
['',
 '/usr/local/lib/python2.7/site-packages/doc2dash-2.1.0.dev0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/zope.interface-4.1.3-py2.7-macosx-10.10-x86_64.egg',
 '/usr/local/lib/python2.7/site-packages/six-1.10.0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/colorama-0.3.3-py2.7.egg',
...

现在是第二种情况,当以交互方式调用时,"path[0]为空字符串,这会让 Python 首先在当前目录中搜索模块。" 当前目录是什么?/Users/laike9m/Dev/Python/TestPython/。(查看这是我机器上的路径,它相当于您的情况下PythonTest的路径)

现在你知道答案:

  1. 为什么python package/test.py会出现 ImportError: No module named package

    因为解释器没有"看到"该包。为了使解释器能够意识到包package,必须将PythonTest添加到sys.path中,但实际上它没有被添加。

  2. 为什么交互模式下可以工作?

    因为现在PythonTest被添加到了sys.path中,所以解释器可以找到包package


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接