详解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中heapq模块的用法
Jun 28 Python
Python3实现带附件的定时发送邮件功能
Dec 22 Python
Python基于Flask框架配置依赖包信息的项目迁移部署
Mar 02 Python
django如何连接已存在数据的数据库
Aug 14 Python
Python判断一个list中是否包含另一个list全部元素的方法分析
Dec 24 Python
10分钟用python搭建一个超好用的CMDB系统
Jul 17 Python
python @propert装饰器使用方法原理解析
Dec 25 Python
Python安装依赖(包)模块方法详解
Feb 14 Python
python右对齐的实例方法
Jul 05 Python
解决导入django_filters不成功问题No module named 'django_filter'
Jul 15 Python
Python入门学习之类的相关知识总结
May 25 Python
使用python求解迷宫问题的三种实现方法
Mar 17 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
PHP通过内置函数memory_get_usage()获取内存使用情况
2014/11/20 PHP
PHP实现的文件上传类与用法详解
2017/07/05 PHP
PHP新特性详解之命名空间、性状与生成器
2017/07/18 PHP
js中document.getElementByid、document.all和document.layers区分介绍
2011/12/08 Javascript
如何让页面在打开时自动刷新一次让图片全部显示
2012/12/17 Javascript
弹出最简单的模式化遮罩层的js代码
2013/12/04 Javascript
Javascript中克隆一个数组的实现代码
2013/12/06 Javascript
js 事件截取enter按键页面提交事件示例代码
2014/03/04 Javascript
jquery实现适用于门户站的导航下拉菜单效果代码
2015/08/24 Javascript
JS+CSS实现经典的左侧竖向滑动菜单效果
2015/09/23 Javascript
非常实用的12个jquery代码片段
2015/11/02 Javascript
使用jQuery加载html页面到指定的div实现方法
2016/07/13 Javascript
将json转换成struts参数的方法
2016/11/08 Javascript
easyUI实现类似搜索框关键词自动提示功能示例代码
2016/12/27 Javascript
AngularJS Select(选择框)使用详解
2017/01/18 Javascript
简单谈谈vue的过渡动画(推荐)
2017/10/11 Javascript
nodejs读取并去重excel文件
2018/04/22 NodeJs
jQuery easyui datagird编辑行删除行功能的实现代码
2018/09/20 jQuery
如何在Vue中抽离接口配置文件
2019/10/31 Javascript
使用Vue Composition API写出清晰、可扩展的表单实现
2020/06/10 Javascript
ssm+vue前后端分离框架整合实现(附源码)
2020/07/08 Javascript
深入了解Vue.js 混入(mixins)
2020/07/23 Javascript
[02:16]DOTA2超级联赛专访Burning 逆袭需要抓住机会
2013/06/24 DOTA
[01:14]英雄,所敬略同——2018完美盛典宣传视频
2018/12/05 DOTA
Django静态资源URL STATIC_ROOT的配置方法
2014/11/08 Python
tensorflow训练中出现nan问题的解决
2018/02/10 Python
Python使用Opencv实现边缘检测以及轮廓检测的实现
2020/12/31 Python
PyCharm 解决找不到新打开项目的窗口问题
2021/01/15 Python
Html+Css+Jquery实现左侧滑动拉伸导航菜单栏的示例代码
2020/03/17 HTML / CSS
Wiggle美国:英国骑行、跑步、游泳、铁人三项商店
2018/10/27 全球购物
幼儿教师自我鉴定
2013/11/02 职场文书
入党自我评价范文
2014/02/02 职场文书
幼儿园教师工作感言
2014/02/15 职场文书
化妆师职业生涯规划书
2014/02/16 职场文书
React自定义hook的方法
2022/06/25 Javascript
mysqldump进行数据备份详解
2022/07/15 MySQL