学习python中的系统路径操作

也是在分析病毒整合的过程,发现了Broad Institute里面的大佬写的软件,因为自己也在学习python的初始阶段,所以就本着学习的兴趣,浏览了源码。 大佬的写的脚本就是高级! 其中我发现了两个比较有意思的东西,第一个是cromwell这个流程空间软件,我测试了下感觉比snakemake快,但是很难学,学习进度缓慢。另一个就是大佬熟练使用各种python的路径操作。最终把十几个python脚本合并在一起形成一个软件。

好羡慕啊,只能说,想拥有

os.path 学习

我搜索了下,python中有两个包都可以做到路径操作,一个是万能的os包中的path模块,一个是适用于高端操作的pathlib。两个都可以了解下。

加载环境

import os
import pathlib
# pyshell 是我自己写的的,运行shell命令,但用的是subprocess模块的功能
import pyshell

首先获得目前所在的工作目录是什么,可以os.getcwd获得。

os.getcwd()
===============OUTPUT================
'/Users/dalena/Data/test'

其次是知道现有的目录结构,好进行一些文件操作的演练

print(pyshell.run_shell("ls")[1])
===============OUTPUT================
__pycache__
file_sum.md5  input1  input2  pivot.xlsx  pyshell.py  step1.res 
tes test.file test.ipynb test.sh test1.sh

可以看到目前的目录下有这些个文件,下面就开始具体的操作

获得绝对路径

这个重要性不言而喻,写脚本最怕的就是依赖文件的路径随着工作目录的更改而找不到,导致报错。所以这个应该是最重要的功能

os.path.abspath("test.sh")
===============OUTPUT================
'/Users/dalena/Data/test/test.sh'

可以看到我们得到了一个sh脚本的绝对路径,再也不用担心工作路径的变化导致脚本报错了,用了都说好。

路径判断

其次针对路径的操作,常常需要判断目标路径的读入和写出是否正常,是否存在,如果不存在肯定直接报错。以下函数都是非常重要且常用的os.path的命令

# 判断文件
os.path.exists("test.sh")
# 判断文件夹
os.path.exists("tes")

分割和合并路径

还有就是我们经常会遇到一些需要合并路径的操作,比如我们知道test文件夹下面有个test.sh的文件,如何得到路径呢。

os.path.join(os.path.abspath("test"),"test.sh")
===============OUTPUT================
'/Users/dalena/Data/test/test/test.sh'

看起来好像多次一举,因为既然我都知道test.sh的存在,我直接写test/test1.sh不就行了,但如果我们想存的是个多个变量名词呢

files = ["test1.sh","test2.sh"]
for file in files:
    print(os.path.join(os.path.abspath("test"),file))
===============OUTPUT================
/Users/dalena/Data/test/test/test1.sh
/Users/dalena/Data/test/test/test2.sh

这样我们很快就了解优势之处了。

其他一些路径操作

除此之外,os.path还有其他有用的命令,比如可以用os.path.commonpath来获得多个路径共有路径,以及os.path.normpath来规范路径,消除一些类似于"./test/../test2"这样的路径,从而达到变成“test2”这样标准路径的作用。

os.path.normpath("./test/../test2")
===============OUTPUT================
'test2'

路径信息

关于目标文件的信息,我也需要获得,比如文件的创建,修改,访问时间,或者文件的大小。以及根据文件的后缀名判断文件类型是否正常等等。这个时候就需要利用下述函数来进行操作了。

函数 功能
os.path.getatime(path) 返回最近访问时间
os.path.getmtime(path) 返回最近文件修改时间
os.path.getctime(path) 返回文件 path 创建时间
os.path.getsize(path) 返回文件大小
os.path.isabs(path) 判断是否为绝对路径
os.path.isfile(path) 判断路径是否为文件
os.path.isdir(path) 判断路径是否为目录
os.path.islink(path) 判断路径是否为链接
os.path.splitext(path) 返回文件的后缀名(最后一个)

pathlib的学习

上述一些常用的,或者说基本的os.path模块中的功能,既然好不容易开始了解python的文件路径操作,就顺带也把进阶版本的pathlib也给了解下。 pathlib需要创建一个Path的对象,然后给予对象进行命令操作。

其实上文的os.path的代码和R看起来非常相似,是不是

但对象这个概念在R里面也有,比如同名不同类的s3 method,或者搭建木的s4 object。只是一般使用R语言的人不太关注,当然也不需要深入了解,R是一个数据科学语言,不需要和编程思维扯太多,既是优势,也是劣势。

不过下文的pathlib操作,就和R不太一样了

创建一个Path对象

p = pathlib.Path("/Users/dalena","Data")
p
===============OUTPUT================
PosixPath('/Users/dalena/Data')

现在p已经是个Path对象了,我们看其输出的结果显示PosixPath,这是因为我在Mac 上进行运行和分析,如果是windows上,就会变成WindosPath,毕竟要知道linux和windows的文件路径差异很大的,斜杠方向都不一样,而且windows还分盘,还忽略大小写。Path对象的的属性和函数可以通过p.__dict__去查看,也可以跟着这篇文章一点点去探索。

Path对象具有诸多属性,但熟悉属性之前,先了解创建Path的方式

# 可以直接输入路径全民
p = pathlib.Path("/Users/dalena/Data")
# 可以输入多个字符,会自动合并
p = pathlib.Path("/Users/dalena“,”Data")
# 也可以用运算符 '/'
p = pathlib.Path("/Users/dalena") / "Data" / "test" / "test.sh"
p
===============OUTPUT================
PosixPath('/Users/dalena/Data/test/test.sh')

Path对象的重要属性

说实话,精力有限,也不可能把一个包全部学会,只要了解其中最常用的部分,剩下的就是遇到问题再来搜索。这样才会最节省时间。 我只能列举一些我个人认为比较常用的一些功能

p.parts
# 可以获得目录各层级的名称
p.root
# 可以获得根目录
p.parents[0]
# 可以获得上级目录,数字以此增加,层级越来越高
p.name
# 可以获得最后的文件名称
p.suffixes[0]
# 可以得到多个后缀名,数字越大,越靠前面
p.stem
# 可以获得文件的名称(不包括后缀名),但是只能去掉最后一个后缀名
===============OUTPUT================
'test'

Path的高阶功能

除了以上属性以外,Path还有一些用于判断,统计,修改的功能函数,下面列举了一些比较重要的功能。

p.is_absolute()
# 可以判断是否是绝对路径
p.match("te*/*.sh")
# 判断是否满足匹配条件
p.relative_to("/Users")
# p对象路径相对于输入的字符的,相对路径,很合适工作目录和脚本目录之间的操作
p.with_name("change.sh")
# 直接更改最后的文件名
p.with_stem("change1")
# 不更换后缀名,但是更改文件名
p.with_suffix(".py")
# 不更改文件名,但是更改后缀名
===============OUTPUT================
PosixPath('/Users/dalena/Data/test/test.py')

Path的高级功能

上述功能都是针对文件,和路径的单纯操作,但是一个路径,会有内容,其内的文件会有属性,而这些操作都需要pathlib更高级的功能。会有可以用iterdir列举文件夹下的所有内容,例如:

p = Path("../")
[x for x in p.iterdir() if x.is_dir()]
===============OUTPUT================
PosixPath('../test'), PosixPath('../Rdata')]

针对其中的文件可以匹配检验下

p = Path("/Users/dalena/Data/test")
list(p.glob("*.sh"))
===============OUTPUT================
dalena'

当然,pathlib还有很多其他的用法,但是这个一般也不常用,或者有其他的方式可以做到。所以学习python路径操作就到这里结束了

完结撒花