详解Python中的路径问题


Posted in Python onSeptember 02, 2020

1. 绝对路径引入

Python 在搜索模块时,依次搜索sys.path里的位置,直到找到模块为止。下面命令可以查看当前的搜索路径:

import sys
print(sys.path)

sys.path的初始值来源于两个(其实还有一些更复杂但不常用的)。一个是系统的PYTHONPATH变量,因此可通过设置该变量,来设置 Python 默认的搜索位置。比如:

export PYTHONPATH=/opt/python:$PYTHONPATH
echo $PYTHONPATH

将该命令放在系统初始化脚本(/etc/environment)或者 BASH 初始化脚本(/~/.bashrc)里,可以对每个新开的窗口有效。

sys.path的另一个来源是当前执行程序所在的目录 (而不是当前目录)。比如当前目录下文件夹./cc下有一个b.py,那么执行./cc/b.py时,./cc(而不是./!)将被加到sys.path

python ./cc/b.py

2. 相对路径引用

上面说的是搜索模块都是指绝对路径引用。对于非系统目录,就需要操纵sys.path。但操纵sys.path有外溢效果,因为它是一个全局变量。对于同一个库里的模块的互相引用,可以考虑使用相对路径:

from . import abc
from .abc import fool
from ..up import foo

但相对路径有两个很恶心的问题,使得用法极为受限。其中一个是:

Note that both explicit and implicit relative imports are based on the name of the current module. Since the name of the main module is always __main__, modules intended for use as the main module of a Python application should always use absolute imports.

包含相对路径 import 的 python 脚本不能直接运行,只能作为 module 被引用。原因正如手册中描述的,所谓相对路径其实就是相对于当前 module 的路径,但如果直接执行脚本,这个 module 的 name 就是__main__, 而不是 module 原来的 name , 这样相对路径也就不是原来的相对路径了,导入就会失败。

在使用相对引用的文件中,不能有 __main__ 方法,只执行作为一个 module 进行引用,而不是直接执行脚本。

举个简单例子。假设./cc/目录下已有一个./cc/b.py(内容为空)。当前目录下的./a.py内容为:

from .cc import b

那么直接运行python ./a.py将会报错:

ModuleNotFoundError: No module named '__main__.cc'; '__main__' is not a package

另一个是常见的错误是: ValueError: attempted relative import beyond top-level package。

在涉及到相对导入时,package所对应的文件夹必须正确的被python解释器视作package,而不是普通文件夹。否则由于不被视作package,无法利用package之间的嵌套关系实现python中包的相对导入。

文件夹被python解释器视作package需要满足两个条件:

1、文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件。

2、不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口)。

补充:在"from YY import XX"这样的代码中,无论是XX还是YY,只要被python解释器视作package,就会首先调用该package的__init__.py文件。如果都是package,则调用顺序是YY,XX。

另外,练习中“from . import XXX”和“from .. import XXX”中的'.'和'..',可以等同于linux里的shell中'.'和'..'的作用,表示当前工作目录的package和上一级的package。

举个例子:

testIm/


--__init__.py


--main.py : from Tom import tom


--Tom/



--__init__.py : print("I'm Tom's __init__!")



--tom.py : from . import tomBrother, from .. import kate,print("I'm Tom!")



--tomBrother.py print(I'm Tom's Brother!)


--Kate/



--__init__.py : print("I'm Kate's __init__!")



--kate.py

运行文件:main.py

结果:

I'm Tom's __init__!
I'm Tom's Brother!
Traceback (most recent call last):
File "D:\PythonLearning\TestIm\main.py", line 3, in <module>
from Tom import tom
File "D:\PythonLearning\TestIm\Kate\kate.py", line 4, in <module>
from .. import kate
ValueError: attempted relative import beyond top-level package
>>>

可以看到from . import tomBrother顺利执行,首先执行了Tom文件夹下的__init__.py文件,后来执行了tomBrother.py文件,但是当执行到“from .. import kate”时报错,这是因为我们是在TestIm文件夹下把main.py文件作为主函数的入口执行的,因此尽管TestIm文件夹中有__init__.py文件,但是该文件夹不能被python解释器视作package,即Tom package不存在上层packge,自然会报错,相对导入时超出了最高层级的package。

修改方法:

test/


--main.py : from testIm.Tom import tom


--testIm/



--__init__.py



--Tom/




--__init__.py : print("I'm Tom's __init__!")




--tom.py : from . import tomBrother, from .. import Kate,print("I'm Tom!")




--tomBrother.py print(I'm Tom's Brother!)



--Kate/



--__init__.py : print("I'm Kate's __init__!")



--kate.py

运行文件:main.py

结果:

I'm top's __init__!
I'm Tom's __init__!
I'm Tom's Brother!!
I'm Kate's __init__!
I'm Tom!

即主函数入口不在TestIm中,则TestIm和其同样包含__init__.py文件的子文件夹都被python解释器视作package,形成相应的嵌套关系。可以正常使用from . import XXX和from .. import XXX。

以上就是详解Python中的路径问题的详细内容,更多关于Python 路径的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python socket.error: [Errno 98] Address already in use的原因和解决方法
Aug 25 Python
Python2.x中str与unicode相关问题的解决方法
Mar 30 Python
Python中在for循环中嵌套使用if和else语句的技巧
Jun 20 Python
python使用邻接矩阵构造图代码示例
Nov 10 Python
python3+PyQt5自定义视图详解
Apr 24 Python
python用BeautifulSoup库简单爬虫实例分析
Jul 30 Python
详解Django-restframework 之频率源码分析
Feb 27 Python
python 弹窗提示警告框MessageBox的实例
Jun 18 Python
Django框架创建项目的方法入门教程
Nov 04 Python
基于Python中isfile函数和isdir函数使用详解
Nov 29 Python
如何使用python实现模拟鼠标点击
Jan 06 Python
Keras: model实现固定部分layer,训练部分layer操作
Jun 28 Python
python dict如何定义
Sep 02 #Python
python基本算法之实现归并排序(Merge sort)
Sep 01 #Python
在pycharm中文件取消用 pytest模式打开的操作
Sep 01 #Python
Python内置函数property()如何使用
Sep 01 #Python
mac安装python3后使用pip和pip3的区别说明
Sep 01 #Python
python3.7.3版本和django2.2.3版本是否可以兼容
Sep 01 #Python
解决python便携版无法直接运行py文件的问题
Sep 01 #Python
You might like
为什么夜间收到的中波电台比白天多
2021/03/01 无线电
ip签名探针
2006/10/09 PHP
在线增减.htpasswd内的用户
2006/10/09 PHP
PHP小技巧之函数重载
2014/06/02 PHP
php的ZipArchive类用法实例
2014/10/20 PHP
php实现中文字符截取防乱码方法汇总
2015/04/29 PHP
php生成word并下载代码实例
2019/03/15 PHP
js计算页面刷新的次数
2009/07/20 Javascript
ASP.NET jQuery 实例9  通过控件hyperlink实现返回顶部效果
2012/02/03 Javascript
php+js实现倒计时功能
2014/06/02 Javascript
JavaScript脚本判断蜘蛛来源的方法
2015/09/22 Javascript
浅谈js的html元素的父节点,子节点
2016/08/06 Javascript
js点击按钮实现水波纹效果代码(CSS3和Canves)
2016/09/15 Javascript
Angularjs中controller的三种写法分享
2016/09/21 Javascript
深入理解Vue 的条件渲染和列表渲染
2017/09/01 Javascript
微信小程序实现倒计时调用相机自动拍照功能
2018/06/10 Javascript
jQuery+Datatables实现表格批量删除功能【推荐】
2018/10/24 jQuery
微信小程序中转义字符的处理方法
2019/03/28 Javascript
利用node 判断打开的是文件 还是 文件夹的实例
2019/06/10 Javascript
vue.js实现数据库的JSON数据输出渲染到html页面功能示例
2019/08/03 Javascript
JavaScript将数组转换为链表的方法
2020/02/16 Javascript
Python strip lstrip rstrip使用方法
2008/09/06 Python
Python基于正则表达式实现文件内容替换的方法
2017/08/30 Python
使用pip安装python库的多种方式
2019/07/31 Python
Python Print实现在输出中插入变量的例子
2019/12/25 Python
tensorflow查看ckpt各节点名称实例
2020/01/21 Python
在Tensorflow中查看权重的实现
2020/01/24 Python
django实现模板中的字符串文字和自动转义
2020/03/31 Python
python 实现读取csv数据,分类求和 再写进 csv
2020/05/18 Python
python中append函数用法讲解
2020/12/11 Python
澳大利亚UGG工厂直销:Australian Ugg Boots
2017/10/14 全球购物
丝芙兰波兰:Sephora.pl
2018/03/25 全球购物
北京振戎融通Java面试题
2015/09/03 面试题
公司任命书模板
2014/06/06 职场文书
小学生感恩老师演讲稿
2014/08/28 职场文书
关于感谢信的范文
2015/01/23 职场文书