加载模块时使用 sys.path.insert(0, path) 和 sys.path(append) 的效果
Effect of using sys.path.insert(0, path) and sys.path(append) when loading modules
我最近遇到了一个 python ImportError 问题,当 运行 在我的本地计算机上找到模块时,在 CI 服务器上找不到模块。我通过将脚本中的 sys.path.append(path)
替换为 sys.path.insert(0, path)
解决了这个问题,其中 path
是字符串模块位置。
因为这是我的模块而不是已安装的包 (related question),为什么路径顺序可以解决这个问题?
因为 python 从 sys.path
列表中的第一个目录开始按顺序检查目录,直到找到它要查找的 .py
文件。
理想情况下,当前目录或脚本目录始终是列表中的第一个元素,除非您修改它,就像您所做的那样。从 documentation -
As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.
所以,很可能,在当前目录(脚本来自 运行)中,您有一个与您尝试从中导入的模块同名的 .py
文件.
此外,关于 ImportError
s 需要注意的一点是,导入错误显示 -
ImportError: No module named main
- 这并不意味着 main.py
被覆盖,不,如果它被覆盖,我们在尝试读取它时不会遇到问题。它上面的某个模块被 .py
或其他文件覆盖。
例子-
我的目录结构是这样的-
- test
- shared
- __init__.py
- phtest.py
- testmain.py
现在从 testmain.py
调用 from shared import phtest
,它工作正常。
现在假设我在 test
目录中引入了一个 shared.py,例如 -
- test
- shared
- __init__.py
- phtest.py
- testmain.py
- shared.py
现在,当我尝试从 testmain.py
执行 from shared import phtest
时,我会收到错误消息 -
ImportError: cannot import name 'phtest'
正如您在上面看到的,导致问题的文件是 shared.py
,而不是 phtest.py
。
我是 Python 的初学者,我发现 Anand 的答案很好,但对我来说很复杂,所以我尝试重新表述:
1) insert
和 append
方法并不特定于 sys.path
并且在其他语言中它们将一个项目添加到列表或数组中并且 :
* append(item)
添加 item
到列表末尾,
* insert(n, item)
在列表的第 n 个位置插入 item
(0
在开头,1
在第一个元素之后,等等...)。
2) 正如Anand所说,python按照路径的顺序在路径的每个目录中搜索导入文件,所以:
* 如果没有文件名冲突,路径的顺序没有影响,
* 如果您查看路径中已定义的函数并使用 append
添加您的路径,您将不会获得您的函数,而是预定义的函数。
但我认为最好使用 append
而不是 insert
以免重载 Python 的标准行为,并为您的文件和方法使用明确的名称.
我最近遇到了一个 python ImportError 问题,当 运行 在我的本地计算机上找到模块时,在 CI 服务器上找不到模块。我通过将脚本中的 sys.path.append(path)
替换为 sys.path.insert(0, path)
解决了这个问题,其中 path
是字符串模块位置。
因为这是我的模块而不是已安装的包 (related question),为什么路径顺序可以解决这个问题?
因为 python 从 sys.path
列表中的第一个目录开始按顺序检查目录,直到找到它要查找的 .py
文件。
理想情况下,当前目录或脚本目录始终是列表中的第一个元素,除非您修改它,就像您所做的那样。从 documentation -
As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.
所以,很可能,在当前目录(脚本来自 运行)中,您有一个与您尝试从中导入的模块同名的 .py
文件.
此外,关于 ImportError
s 需要注意的一点是,导入错误显示 -
ImportError: No module named main
- 这并不意味着 main.py
被覆盖,不,如果它被覆盖,我们在尝试读取它时不会遇到问题。它上面的某个模块被 .py
或其他文件覆盖。
例子-
我的目录结构是这样的-
- test
- shared
- __init__.py
- phtest.py
- testmain.py
现在从 testmain.py
调用 from shared import phtest
,它工作正常。
现在假设我在 test
目录中引入了一个 shared.py,例如 -
- test
- shared
- __init__.py
- phtest.py
- testmain.py
- shared.py
现在,当我尝试从 testmain.py
执行 from shared import phtest
时,我会收到错误消息 -
ImportError: cannot import name 'phtest'
正如您在上面看到的,导致问题的文件是 shared.py
,而不是 phtest.py
。
我是 Python 的初学者,我发现 Anand 的答案很好,但对我来说很复杂,所以我尝试重新表述:
1) insert
和 append
方法并不特定于 sys.path
并且在其他语言中它们将一个项目添加到列表或数组中并且 :
* append(item)
添加 item
到列表末尾,
* insert(n, item)
在列表的第 n 个位置插入 item
(0
在开头,1
在第一个元素之后,等等...)。
2) 正如Anand所说,python按照路径的顺序在路径的每个目录中搜索导入文件,所以:
* 如果没有文件名冲突,路径的顺序没有影响,
* 如果您查看路径中已定义的函数并使用 append
添加您的路径,您将不会获得您的函数,而是预定义的函数。
但我认为最好使用 append
而不是 insert
以免重载 Python 的标准行为,并为您的文件和方法使用明确的名称.