天天看点

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

提示:苦不堪言!实际工作中肯定是 PyCharm 用得多,但学习 Python 的话,还是感觉 Anaconda(Spyder)舒服,偶尔还想尝试一下直接在 Python IDLE 里用命令行执行脚本。于是,我就遇到了很多 ModuleNotFoundError & ImportError 提示。痛定思痛,终于决定把这些一点一点记录下来,以便参考、分享。

目录

  • 1 前言
    • `提示:以下是本篇文章正文内容,下面案例可供参考`
  • 2 sys.path 是什么?
  • 3 sys.path[0] 在不同解释器中返回值不同
    • 3.1.在官方 IDE 中默认返回空字符串
    • 3.2.在 Spyder 的 IPython 控制台 返回一个“\\Anaconda\\”目录
    • 3.3. 在 Spyder 的脚本文件运行返回当前工作目录
    • 3.4. 在 PyCharm 的 Python Console 返回一个“\\JetBrains\\”目录
    • 3.5. 在 PyCharm 的 Terminal 默认返回空字符串
    • 3.6. 在 PyCharm 的脚本文件运行返回当前工作目录
  • 4 总结

1 前言

提示:这里可以添加本文要记录的大概内容:

本文从了解 sys.path 开始,然后查看当前工作目录在 sys.path 中的不同表达。盼望这样可以清楚了解不同解释器运行同一脚本可能导致的导入错误提示。

【环境】

Win7-64bit

Anaconda (Spyder 4.2.5, Python 3.7.10)

PyCharm 2020.3 (调用 conda 环境)

提示:以下是本篇文章正文内容,下面案例可供参考

2 sys.path 是什么?

import sys

type(sys.path)
list   
           

先查一下官方文档:

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

解读如下:

  1. sys.path 返回一个列表,元素包含环境变量 PYTHONPATH 和一条默认路径。
  2. “模块搜索路径中的第一个条目是包含输入脚本的目录(如果有的话)。 否则,第一个条目是当前目录,这是执行交互式 shell、-c 命令或 -m 模块时的情况。”
  3. 对于列表而言,第一个条目即 sys.path[0]。
  4. 以命令行执行脚本(交互式),则脚本目录不可用,即 sys.path[0] 为空字符串。为什么是空字符串?因为脚本目录找不到。所以,就会引导进入当前工作目录。当然,空字符串的问题情况较多,后面有详述。
  5. 可以向这个列表添加目录达到初始化导入的目的。向一个列表添加元素可以用 .append(), .insert(), .extend()
  6. 修改 sys.path 的好处在于简单,而且代码执行之后,重启解释器,这个加入的目录不在其内,就避免了很多混乱。换句话说,不影响下一个项目的运行——但是需要重启解释器。
  7. 关于重启解释器这个操作,在 Python IDLE 就是关闭了再打开,而在 Spyder 则是“重启 IPython 内核”,在 PyCharm 则是一个脚本文件里执行了添加目录至 sys.path 并不影响其他脚本文件。
  8. 也有博主认为这种添加“动态改变sys.path会使静态分析工具失效”,在大型项目里带来困难,称之为“软件开发的灾难”。没看懂。
# 这里假设需要添加当前工作目录(示例而已)
import os
import sys

w_dir = os.getcwd()

# 方法1
sys.path.append(w_dir)

# 方法2
sys.path.insert(0, w_dir)

# 方法3
ls = []
ls.append(w_dir)
sys.path.extend(ls)
           

3 sys.path[0] 在不同解释器中返回值不同

3.1.在官方 IDE 中默认返回空字符串

这一点前面已经解释了。示例如下:

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

查看当前工作目录

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

3.2.在 Spyder 的 IPython 控制台 返回一个“\Anaconda\”目录

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

但是,仔细查看 sys.path[0] 仍然是有一个空字符串的,只不过不是第一个:

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

查看当前工作目录

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

3.3. 在 Spyder 的脚本文件运行返回当前工作目录

将前面的代码写入脚本文件,在 Spyder 里的运行结果同上。

3.4. 在 PyCharm 的 Python Console 返回一个“\JetBrains\”目录

由于我使用 PyCharm 调用 conda 环境,所以 Python Console 也与 Spyder 的 IPython 控制台相通,但细节不同。

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

sys.path 并未包含空字符串,而是包含了当前工作目录。

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

查看当前工作目录如下:

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

3.5. 在 PyCharm 的 Terminal 默认返回空字符串

Python Console 与 Terminal 并不相同。后者即 cmd。

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结
【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

3.6. 在 PyCharm 的脚本文件运行返回当前工作目录

代码如下(示例):

import os
import sys

# 查看 sys.path
print("sys.path[0]:", sys.path[0])
print("len(sys.path):", len(sys.path))
for path in sys.path:
    print("sys.path:", path)

# 查看当前工作目录
print("当前工作目录:", os.getcwd())
           

运行结果如下:

【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结

4 总结

  1. 当前工作目录在 sys.path 中的表达颇为不同,跟解释器有关:有的表达为空字符串,有的直接以当前工作目录代替空字符串。由此,sys.path[0] 的值亦有不同。
  2. 最终还是回归官方文档,正确理解并使用 sys.path。
    【ModuleNotFoundError 与 ImportError】之 sys.path1 前言2 sys.path 是什么?3 sys.path[0] 在不同解释器中返回值不同4 总结