详解Python中的路径问题
1.绝对路径引入
Python在搜索模块时,依次搜索sys.path里的位置,直到找到模块为止。下面命令可以查看当前的搜索路径:
importsys print(sys.path)
sys.path的初始值来源于两个(其实还有一些更复杂但不常用的)。一个是系统的PYTHONPATH变量,因此可通过设置该变量,来设置Python默认的搜索位置。比如:
exportPYTHONPATH=/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.importabc from.abcimportfool from..upimportfoo
但相对路径有两个很恶心的问题,使得用法极为受限。其中一个是:
Notethatbothexplicitandimplicitrelativeimportsarebasedonthenameofthecurrentmodule.Sincethenameofthemainmoduleisalways__main__,modulesintendedforuseasthemainmoduleofaPythonapplicationshouldalwaysuseabsoluteimports.
包含相对路径import的python脚本不能直接运行,只能作为module被引用。原因正如手册中描述的,所谓相对路径其实就是相对于当前module的路径,但如果直接执行脚本,这个module的name就是__main__,而不是module原来的name,这样相对路径也就不是原来的相对路径了,导入就会失败。
在使用相对引用的文件中,不能有__main__方法,只执行作为一个module进行引用,而不是直接执行脚本。
举个简单例子。假设./cc/目录下已有一个./cc/b.py(内容为空)。当前目录下的./a.py内容为:
from.ccimportb
那么直接运行python./a.py将会报错:
ModuleNotFoundError:Nomodulenamed'__main__.cc';'__main__'isnotapackage
另一个是常见的错误是:ValueError:attemptedrelativeimportbeyondtop-levelpackage。
在涉及到相对导入时,package所对应的文件夹必须正确的被python解释器视作package,而不是普通文件夹。否则由于不被视作package,无法利用package之间的嵌套关系实现python中包的相对导入。
文件夹被python解释器视作package需要满足两个条件:
1、文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件。
2、不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口)。
补充:在"fromYYimportXX"这样的代码中,无论是XX还是YY,只要被python解释器视作package,就会首先调用该package的__init__.py文件。如果都是package,则调用顺序是YY,XX。
另外,练习中“from.importXXX”和“from..importXXX”中的'.'和'..',可以等同于linux里的shell中'.'和'..'的作用,表示当前工作目录的package和上一级的package。
举个例子:
testIm/ --__init__.py --main.py:fromTomimporttom --Tom/ --__init__.py:print("I'mTom's__init__!") --tom.py:from.importtomBrother,from..importkate,print("I'mTom!") --tomBrother.pyprint(I'mTom'sBrother!) --Kate/ --__init__.py:print("I'mKate's__init__!") --kate.py
运行文件:main.py
结果:
I'mTom's__init__!
I'mTom'sBrother!
Traceback(mostrecentcalllast):
File"D:\PythonLearning\TestIm\main.py",line3,in
fromTomimporttom
File"D:\PythonLearning\TestIm\Kate\kate.py",line4,in
from..importkate
ValueError:attemptedrelativeimportbeyondtop-levelpackage
>>>
可以看到from.importtomBrother顺利执行,首先执行了Tom文件夹下的__init__.py文件,后来执行了tomBrother.py文件,但是当执行到“from..importkate”时报错,这是因为我们是在TestIm文件夹下把main.py文件作为主函数的入口执行的,因此尽管TestIm文件夹中有__init__.py文件,但是该文件夹不能被python解释器视作package,即Tompackage不存在上层packge,自然会报错,相对导入时超出了最高层级的package。
修改方法:
test/ --main.py:fromtestIm.Tomimporttom --testIm/ --__init__.py --Tom/ --__init__.py:print("I'mTom's__init__!") --tom.py:from.importtomBrother,from..importKate,print("I'mTom!") --tomBrother.pyprint(I'mTom'sBrother!) --Kate/ --__init__.py:print("I'mKate's__init__!") --kate.py
运行文件:main.py
结果:
I'mtop's__init__!
I'mTom's__init__!
I'mTom'sBrother!!
I'mKate's__init__!
I'mTom!
即主函数入口不在TestIm中,则TestIm和其同样包含__init__.py文件的子文件夹都被python解释器视作package,形成相应的嵌套关系。可以正常使用from.importXXX和from..importXXX。
以上就是详解Python中的路径问题的详细内容,更多关于Python路径的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。