深入理解Python解析器对模块位置的搜索顺序

最初接触python时通过http://www.runoob.com/python/python-modules.html的教程学习python的基础知识。

看模块和包时看到这么一段话:


定位模块

当你导入一个模块,Python解析器对模块位置的搜索顺序是:

  • 当前目录
  • 如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
  • 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。


后面两条都没啥问题,当前目录这句话却让我理解为凡是两个python脚本在同一目录下,一定可以直接互相import,但是实际敲代码试的时候发现不是这回事。

依据上段话内容代码举例引出问题:

ubuntu/python3.5.2环境下,在/home/xxx/workspace目录下创建文件夹package。

package目录下创建脚本print.py,写入如下代码:

1 def print_text(x):
2     print(x)

继续创建脚本__init__.py,写入如下代码:

1 from print import print_text

在workspace目录下创建脚本main.py,写入如下代码:

1 import package
2 package.print_text('Hello world!')

最终文件结构如下:

-/home/xxx/workspace/
    -main.py
    -package
        -__init__.py
        -print.py

按照之前错误的理解执行main.py会在终端输出hello word,实际上在终端中cd到/home/xxx/workspace/目录,python3 main.py运行main.py后会得到如下报错信息:

Traceback (most recent call last):
  File "/home/chen/workspace/main.py", line 1, in <module>
    import package
  File "/home/chen/workspace/package/__init__.py", line 1, in <module>
    from print import print_text
ImportError: No module named 'print'

即虽然__init__.py和print.py在同一级目录下,但是__init__.py无法搜索到print.py所在目录。


在__init__.py代码中添加打印系统环境变量的代码如下:

1 import sys
2 # 打印系统path变量
3 print(sys.path)
4 from print import print_text

重新执行main.py,输出信息变为

['/home/xxx/workspace/', '/usr/local/lib/python3.5/dist-packages/setuptools-18.1-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pip-7.1.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/howdoi-1.1.9-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/requests_cache-0.4.12-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/Pygments-2.1.3-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pyquery-1.2.17-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/cssselect-1.0.0-py3.5.egg', '/usr/lib/python3/dist-packages', '/usr/local/lib/python3.5/dist-packages/tornado-4.4.2-py3.5-linux-x86_64.egg', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages']
Traceback (most recent call last):
  File "/home/xxx/workspace/main.py", line 1, in <module>
    import package
  File "/home/workspace/package/__init__.py", line 3, in <module>
    from print import print_text
ImportError: No module named 'print'

可以看到__init__.py所在目录/home/xxx/workspace/package/确实不在系统环境变量中,取而代之的则是main.py所在的目录。

那么是否当前目录实际上仅仅指当前所运行的程序的所在目录呢?如果成立,将__init__.py代码修改为如下一定可以正常输出hello world,试下

1 from package.print import print_text

重新执行main.py,果然成功输出Hello world!

继续验证,如果上面猜测成立,还一定能得出直接执行__init__.py不会报错的结论,试下,__init__.py的代码改为

1 import sys
2 print(sys.path)
3 from print import print_text
4 print_text('Hello world!')

执行main.py,输出如下:

['/home/xxx/workspace/package', '/usr/local/lib/python3.5/dist-packages/setuptools-18.1-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pip-7.1.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/howdoi-1.1.9-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/requests_cache-0.4.12-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/Pygments-2.1.3-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pyquery-1.2.17-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/cssselect-1.0.0-py3.5.egg', '/usr/lib/python3/dist-packages', '/usr/local/lib/python3.5/dist-packages/tornado-4.4.2-py3.5-linux-x86_64.egg', '/home/xxx/workspace/package', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages']
Hello world!

可以看到,环境变量打印结果中确实有一条路径已经变为__init__.py所在的目录,并且hello world打印成功!

至此得出结论:当前目录指当前运行程序的所在目录。

所以在import非程序入口的同级目录下其它python脚本时,我们有以下两种可行的做法

1.引入模块的路径写为相对于入口程序所在路径的相对路径,例如上面例子__init__.py写为

1 from package.print import print_text

2.在脚本头部将当前文件的所在目录直接插入解释器搜索的系统path中,例如将__init__.py改写为

1 import sys
2 sys.path.append('/home/xxx/workspace/package/')
3 from print import print_text

原文https://www.cnblogs.com/chenstring/p/blog_01.html 感谢

猜你喜欢

转载自blog.csdn.net/Lxy_Python/article/details/81778743
今日推荐