一、任务
小编初学Python时,总是喜欢用sys.argv[0]l来获取当前脚本的全路径名,用os.path.abspath("test")来获取当前脚本同一目录下的test目录的绝对路径,
用IDLE加载脚本并执行脚本的时候,这没问题。
但是,一旦我们运行Python涉及到命令行和嵌套调用,问题就比较复杂了,有的时候会出错。为此,我们有必要探讨什么是获取当前脚本的全路径名及其所在的绝对路径的正确姿势。
注意:本文在讨论中不区分目录、路径、文件夹,认为三者是同一概念。
二、程序
假定我们所考察的Python脚本是 D:\ftp\getpath\getpath.py,内容如下:
另有一个配套测试的Python文件D:\ftp\main.py,内容如下:
三、测试
第一、通过IDLE运行getpath.py,结果如下:
Python脚本的绝对路径:D:\ftp\getpath\getpath.py
------------------------------------------------------
os.path.abspath('.'):D:\ftp\getpath
os.getcwd() :D:\ftp\getpath
sys.path[0] :D:\ftp\getpath
sys.argv[0] :D:\ftp\getpath\getpath.py
__file__ :D:\ftp\getpath\getpath.py
------------------------------------------------------
第二、命令行窗口的当前目录在C盘,通过命令行来运行getpath.py,命令如下:
C:\>python D:\ftp\getpath\getpath.py
运行结果如下:
Python脚本的绝对路径:D:\ftp\getpath\getpath.py
------------------------------------------------------
os.path.abspath('.'):C:\
os.getcwd() :C:\
sys.path[0] :D:\ftp\getpath
sys.argv[0] :D:\ftp\getpath\getpath.py
__file__ :D:\ftp\getpath\getpath.py
------------------------------------------------------
第三、在命令行中将当前目录切换为Python脚本所在目录,再用命令行运行getpath.py。
命令如下:
D:\ftp\getpath>python getpath.py
运行结果如下:
Python脚本的绝对路径:D:\ftp\getpath\getpath.py
------------------------------------------------------
os.path.abspath('.'):D:\ftp\getpath
os.getcwd() :D:\ftp\getpath
sys.path[0] :D:\ftp\getpath
sys.argv[0] :getpath.py
__file__ :getpath.py
------------------------------------------------------
第四、在命令行中将当前目录切换为Python脚本所在目录的父目录,再用命令行运行getpath.py。
命令如下:
D:\ftp>python getpath\getpath.py
运行结果如下:
Python脚本的绝对路径:D:\ftp\getpath\getpath.py
------------------------------------------------------
os.path.abspath('.'):D:\ftp
os.getcwd() :D:\ftp
sys.path[0] :D:\ftp\getpath
sys.argv[0] :getpath\getpath.py
__file__ :getpath\getpath.py
------------------------------------------------------
第五、在命令行窗口中将当前目录设为c:\,运行main.py,命令如下:
C:\>python D:\ftp\main.py
运行结果如下:
Python脚本的绝对路径:D:\ftp\getpath\getpath.py
------------------------------------------------------
os.path.abspath('.'):C:\
os.getcwd() :C:\
sys.path[0] :D:\ftp
sys.argv[0] :D:\ftp\main.py
__file__ :d:\ftp\getpath\getpath.py
------------------------------------------------------
四、总结
(1)、os.path.abspath('.')和os.getcwd()的值永远跟当前目录一致。
如果是用IDLE加载脚本文件运行,则脚本文件所在目录是当前目录。
(2)、sys.path[0]的值是主调文件所在的绝对目录,所谓主调文件是直接被Python所调用的文件。
(3)、sys.argv[0]的值是主调文件的相对目录。
用os.path.abspath(sys.argv[0])可完美表示主调文件的绝对路径。
(4)、__file__的值是当前脚本文件的相对目录。
用os.path.abspath(__file__)可完美表示当前脚本文件的全路径名 。
五、结论
要获取当前脚本的全路径名,用os.path.abspath(__file__)是唯一完美的方法。
要获取当前脚本的绝对路径,用os.path.split(os.path.abspath(__file__))[0]是唯一完美的方法。
六、建议
1、由于Python脚本可以相互调用,所以我们很难知道主调文件跟当前脚本文件的路径之间有什么关系。建议可能被调用的脚本文件当中,如果函数参数有涉及到路径inpath的,一定要视为绝对路径,
不要自作聪明地用os.path.abspath(inpath)来变成绝对路径。当然,主调文件调用被调用脚本的函数时,如果涉及到路径,一定要传递绝对路径过去。
2、加载自定义扩展包的时候,一定要用绝对路径,不要用相对路径。例如,本文的main.py里面,如果将
sys.path.append(r"d:\ftp\getpath")
改为
sys.path.append(os.path.abspath("getpath"))
的话,在IDLE中运行不会有问题,但如果在命令方式运行main.py,可能就会有问题。