python学习个人总结

树的遍历、堆排序、文件操作、正则表达式、os等

一、树的遍历
1、二叉树的遍历
遍历:迭代所有元素一遍。
树的遍历:对树中所有的元素不重复的访问一遍,也成扫描
广度优先遍历:层序遍历
深度优先遍历:前序、中序、后续遍历。
遍历序列:将树中所有元素遍历一遍后,得到的元素序列。将层次结构转换成了线性结构。
2、层序遍历:
按照数的层次,从第一层开始,自左向右遍历元素
遍历顺序ABCDEFGHI

3、深度优先遍历:
设树的根节点为D,左子树为L。右子树为R,且要求L一定在R之前,有以下几种遍历方式:
前序遍历:DLR 也是先序遍历,也叫做先根遍历。DLR
中序遍历,也叫中根遍历。LDR
后序遍历:也叫做后根遍历。LRD
1)前序遍历DLR
从根结点开始,先从左子树后右子树。
遍历顺序:A BDGH CEIF

2)中序遍历LDR:
从根节点的左子树开始遍历,然后是根结点,在右子树。
每个子树内部,也是先左子树,后根结点,在右子树;

3)后序遍历
先左子树,后右子树,在根节点。
每个子树内部依然是先左子树,后右子树,在根节点;

4、堆排序:Heap
堆是一个完全二叉树。
每个非叶子结点都要大于或者等于其它左右孩子结点的值成为大顶堆。
每个非叶子结点都要小于或者等于其左右孩子结点的值成为小顶堆。
根结点一定是大定对中的最大值,一定是小顶堆中最小的值。
1)大顶堆,完全二叉树的每个非叶子结点都要大于或者等于其左右孩子结点的值。
根结点一定是大顶堆中最大值。

2)小顶堆:
完全二叉树的每个非叶子结点都要小于或者等于其左右孩子结点的值。
根结点一定是小顶堆中最小的值。
3)构件完全二叉树,
将待排序数字为30,20,80,40,50,10,60,70,90
构件一个完全二叉树存放数据,并根据性质5对元素进行编号。
构造一个列表为[0,30,20,80,40,50,10,60,70,90]
4)构造大顶堆———核心算法
度数为2的结点A,如果他的左右孩子结点的最大值比他的值大,将这个最大值与该结点交换。
度数为1的节点,如果他的左孩子的值大于他,则交换。
如果结点被交换到新的位置,还需和其它孩子结点重复上面的过程。
5)起点结点的选择。
从完全二叉树的最后一个结点的双亲结点开始,及最后一层的最后边叶子结点的父结点开始。
结点树为n,则其实结点的编号为n//2
6)下一个结点的选择:
从其实结点开始向左找其同层结点,到头后在从上一层的最右边结点开始继续向左逐个查找,直至根结点。
7)大顶堆目标,确保每个结点的值都比左右点的值大。
8)排序:
将大顶堆根节点 这个最大值和最后一个叶子结点交换,那么最后一个叶子结点就是最大值,将这个叶子节点排除在待排序结点之外。
从根节点开始(新的根节点),重新调整为大顶堆,重复上一步。

9)大顶堆总结:最大值一定在最顶层。次大值一定在第二层。
堆排序总结:
1、时间复杂度o(nlogn)
2、由于堆排序对原始记录的排序状态并不敏感,因此无论是最好、最坏和平均时间复杂度均为o(nlogn)。时间比较稳定。
3、空间复杂度。只是使用了一个交换用的空间,空间复杂度就是o(1)
4、稳定性,不稳定的排序算法。
熟悉树的概念之上的。

二、无文件操作IO
1、冯诺依曼体系。
Cpu由运算器和控制器组成:
运算器,完成各种算数操作、逻辑运算、数据传输等数据加工处理。
控制器,控制程序的执行。
存储器,用于记忆程序和数据,例如内存。
输入设备,将数据或者程序输入到计算机中,例如键盘,鼠标。
输出设备:将计算机处理结果 展示给用户,例如显示器,打印机等。
2、一般说IO操作,指的是文件IO,如果指的是网络IO,那么就是网络IO操作。

3、文件IO常用操作
column column
open 打开
read 读取
write 写入
close 关闭
readline 行读取
readlines 多行读取
seek 文件指针操作
tell 指针位置
4、打开操作。
Open(file,mode=’r’,buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)

Open 打开一个文件,返回一个文件对象(流对象)和文件描述符,打开文件失败,返回异常。
基本使用:
f = open(‘test’)
print(f.read())
f.close
文件操作中,最常用的操作就是读和写。
文件的访问模式也有两种:文本模式和二进制模式。不同模式,函数操作不尽相同,表现的结果也不一样。

5、poen的参数
1)file:
打开或者创建的文件名,如果不指定路径,默认是当前路径。
2)mode模式
描述字符 意义
r 缺省的,表示只是打开
w 只是打开
x 创建并写入一个新的文件
a 写入打开,如果文件存在,则追加
t 缺省的,文本模式
+ 读写打开一个文件,给原来只读、只写方式打开缺失的读或者写的能力

3)编码
Windows下面:GBK CP936
Linux下面是:UTF-8
文件操作中,最常见的就是读和写。
文件访问的模式有两种:文本模式和二进制模式;不同模式下,函数的执行.
W特性是:没有的话创建,有的话直接覆盖。
Open默认是只读模式r打开已经存在的文件。
4)#基本练习
#只读的
f = open(‘test’) #等价于 f = open(‘open’,‘r’)
f.read()
# f.write(‘abc’)
f.close()
#只写
f = open(‘test’,’w’)
print(f.write(‘abc’))
f.close()
Print 输入3,显示的是输入的是三个字符。

5)总结
Open模式是只读模式r打开已经存在的文件。
(1)r
只读打开文件,如果使用write方法,会抛出异常
如果文件不存在,抛出FileNotFoundError异常
(2)w
表示只写方式打开,如果读取则抛出异常。
如果文件不存在,则直接创建文件。
如果文件存在,则清空里面的内容。
(3)x
文件不存在直接创建。
文件存在的话直接抛出异常。
创建新文件是只写的。
f = open(‘test2′,’x’)
#print(f.read())
print(f.write(‘abcd’))
f.close

(4) a
文件存在,只写打开,追加内容。
文件不存在,创建后,只写打开,追加内容。
f = open(‘test1′,’a’)
# print(f.read())
f.write(‘abcd’)
f.close()
(5)r 只读,wxa都是只写
wxa 都可以产生新文件;
w不管文件存在与否,都会生成全新内容的文件;
a不管文件是否存在,都能在打开的文件尾部追加;
x 必须要求文件事先不存在,自己造一个新的文件。

(6)文本模式t
字符流,将文件的字节按照某种字符编码理解,按照字符操作。Open的默认莫得就是rt。
默认都是文本字符。

(7)二进制模式b
字节流,将文件就按照字节理解,与字符编码无关,二进制模式操作时,字节操作使用beyes类型.
f = open(‘test1′,’rb’)
s = f.read()
print(type(s))
print(s)
f.close()
控制台输出:
<class ‘bytes’>
b’abcd’
f = open(‘test3′,’wb’)
s = f.write(“中国”.encode())
print(s)
f.close()
控制台输出:
6

(8)+号模式功能
为r、w、a、x提供缺失的读写功能,但是,获取文件对象依旧按照r、w、a、x自己的特征。
+不能单独使用,可以认定他是为前面的模式做增强功能的。
f = open(‘test1′,’r+’)
s = f.write(‘hijkl’)
print(f.read())
f.close()

(9)b
里面是二进制字节,,其余是字符
Read(参数列表)
文本模式下指的是字符。
二进制 下指的字节。
6、文件指针
上面的例子中,说明有一个指针。
1)文件指针,指向当前字节的位置
mode=r,指针起始在0
mode=a,起始位置在EOF
tell()显示指针所在位置。指的是字节的偏移量。
seek(offset[,whence]) 移动文件指针位置,offest偏移多少字节,whence是指在哪里开始。
2)文本模式下:
Whence为0的时候,文件开头向后偏移量。Offset只是接受正整数。
为1表示当前位置,offest只接受0
为2的时候表示从EOF开始,offest只接受0
3)二进制模式下:
Whence缺省值0,文件开头向后偏移,offest只是接受正整数。
为1表示当前位置,offest可以接受正负整数。
为2表示从EOF开始,offest可以接受正负整数。
二进制模式支持任意起点的偏移,从头、从尾,从中间位置开始,向后seek可以超界,但是向前就不可以,否则抛出异常.

f = open(‘test2′,’r+’)
print(f.tell())
f.read()
print(f.tell())
f.seek(0)
print(f.read())
中文模式只是支持双字节便宜否则报错,因为中文都是双字节的、
7、buffering缓冲区:
-1表示使用缺省大小的buffer,如果是二进制模式,使用io.DEFAULT_BUFFER_SIZE值。默认值4096或者8192.
如果是文本模式,如果是终端设备,是行缓存方式,如果不是,则使用二进制模式的策略。
0只在二进制模式使用,表示关buffer
1只在文本模式使用,表示行缓冲。遇到换行符的时候才flush。
大于1用于指定buffer。

buffer缓冲区:
缓冲区一个内存空间,一般来说是一个FIFO队列,到缓冲区满了或者达到阈值,数据才会到flush到磁盘。文本模式下不能关闭buffer。。
当缓冲区满了就该flush。
flush()将缓冲区数据写入磁盘。
close()关闭前会调用flush()
io.DEFAULT_BUFFER_SIZE缺省缓冲区大小、字节。
buffering
buffering=-1 t和b,都是io.DEFAULT_BUFFER_SIZE
buffering=0 b关闭缓冲区 t不支持
buffering=1 b就一个字节 t行缓冲,遇到换行符才flush
Buffering>1 B模式表示行缓冲从大小,缓冲的值可以超过io.DEFAULT_BUFFER_SIZE,直到设置的值超出后才把缓冲区flush
t 模式,是io.DEFAULT_BUFFER_SIZE

Buffering=-1 t和b都是size
Buffering=0 b关闭缓冲区 t没有
Buffering=1 b就一个字节 t行换成,遇到换行符才flush
Buffering>1 b模式表示行缓冲大小。
f = open(‘test4′,’w+b’)
print(io.DEFAULT_BUFFER_SIZE)

总结:
1、文本模式中,一般都默认使用缓冲区大小。
2、二进制模式。是一个个字节的操作,可以指定buffer的大小。
3、一般来说,默认缓冲区大小就是个比较好的选择,除非明确知道,否则不调整。
4、一般编程中,明确知道需要写磁盘了,都会手动调用一次flush,而不是等到自动flush或者close。

8、encoding:编码,仅文本模式使用:
None表示缺省编码。依赖操作系统。Windows、linux下的如下代码。
Windows下缺省GBK()
Linux下缺省UTF-8
f = open(‘test2′,’w’)
print(f.write(‘啊’))
# print(f.read())
f.close()

9、其它参数:
Errors:什么样的编码错误表示将被捕获。
None和strict表示有编码错误将抛出valueError异常,ignore表示异常。
10、Newline:
文本模式中,换行的转换,可以为None、空串””、’\r’、’\n’、’\r\n’
读时候,None表示’\r’,’\n’,’\r\n’都被转换为’\n’:”表示不会自动转换通用换行符,其它合法字符表表示换行符就是指定字符,就会按照指定字符分行。
写时,none表示’\n’都会被替换为系统缺省行分隔符os.linesep;’\n’或”表示’\n’不替换,其它合法字符表示’\n’会被替换为指定的字符。

11、Closedfd 关闭文件描述符,True表示关闭。False会在文件关闭后保持这个描述符,fileobj.fileno()查看这个特性。

12、Read

Read(size=-1) size表示读取的多少个字符或者字节,负数或者None表示读取到EOF

13、行读取:
Readline(size=-1) 一行行读取内容,size设置以后就按照要求设置的取几个字节或者字符。

Readlines(hint=1)
读取所有行的列表,指定hint()。

14、Write(写),把字符串s写入到文件中并返回字符的个数
Writelines(lines),将字符串列表写入文件。

15、Close
flush并关闭对象。
文件已经关闭,再次关闭没有任何效果。

16、其它:
Seekable()是否可以seek
Readable()是否可读
Writable()是否可读
Closed是否已经关闭

17、上下文管理:
1)异常处理,当出现异常的时候,拦截异常,但是,因为许多代码都可能出现OSError异常,不好判断因为资源限制产生的。
f = open(‘test’)
try:
f.write(‘abc’)
finally:
f.close()
使用finally可以保证打开的文件可以被关闭

2)、上下文管理
一种特殊的语法,交给解释去去释放文件对象
with open(‘test’) as f:
f.write(‘abc’)

f.closed
f1 = open(‘test’)
with f1:
f1.write(‘abc’)
f.closed

With f:
文件管理就自持上下文管理,在退出with上下的时候,会调用close。
With open(‘test’) as f:
使用with …as关键字。With…as不是函数。上下文管理的语句块并不会开启新的作用域。With语句块执行完的时候,会自动关闭文件对象。
对于类似于文件对象的IO对象,一般来说都需要在不使用的时候关闭、注销,以释放资源。
IO被打开的时候,会获得一个文件描述符,计算机资源是有限的,所以操作系统都会做限制,就是为了保护计算机的资源不要被完全的耗尽,资源是共享的,不是独占的。
一般情况下,除非特别声明情况下,不得提高资源的限制值来解决问题。

18、习题:
1)给定一个源文件,实现copy功能。
src = ‘test.txt’
dest = ‘test1.txt’
def copy(src,dst):
with open(src,’r+’)as f:
with open(dest,’w+’) as f1:
f1.write(f.read())
思路:打开源文件的读功能,打开文件2的写功能,把源文件读出来的内容直接写入到文件2中。
2)有一个文件,对文件进行统计
#第一步初步代码
d = {}
with open(‘sample.txt’,encoding=’UTF-8′)as f:
for line in f:
wrods = line.split()
for word in wrods:
d[word] = d.get(word,0)+1
print(sorted(d.items(),key=lambda item:item[1],reverse=True)[0:10])
#打印出:[(‘the’, 124), (‘is’, 60), (‘a’, 54), (‘path’, 52), (‘and’, 39), (‘of’, 33), (‘if’, 32), (‘to’, 31), (‘or’, 24), (‘Return’, 22)]
#第二步。
def makekey(x):
chars = set(r”””/#@!%&~~*(){}\[].:””-+|’=»'”””)
key = x.lower()
ret = []
for c in key:
if c in chars:
ret.append(”) #如果为特殊符号,则用空
else:
ret.append(c)
print(ret)
return ”.join(ret).split() #按照空拼接字符串。

d = {}
with open(‘sample.txt’,encoding=’UTF-8′) as f:
for line in f:
words = line.split()
for wordlist in map(makekey,words):
for word in wordlist:
d[word] =d.get(word,0) +1

print(sorted(d.items(),key=lambda item:item[1],reverse=True)[0:10])
#第三步
def makekey(x):
chars = set(r”””/#@!%&~~*(){}\[].:””-+|’=»'”””)
key = x.lower()
ret = []
for c in key:
if c in chars:
ret.append(”)
else:
ret.append(c)
# print(ret)
return ”.join(ret).split()

d = {}
with open(‘sample.txt’,encoding=’UTF-8′) as f:
for line in f:
words = line.split()
for wordlist in map(makekey,words):
for word in wordlist:
d[word] =d.get(word,0) +1

# print(sorted(d.items(),key=lambda item:item[1],reverse=True)[0:10])

def top(n):
for i,t in enumerate(sorted(d.items(),key=lambda item:item[1],reverse=True)):
if i>n:
return
yield t

for i in top(10):
print(i)

三、stringIO和bytesIO
1、stringIO文件。

2、stringIO
Io模块中的类 from io import stringIO
内存中,开辟的一个文本模式的buffer,可以文件对象一样操作。
当close方法被调用的时候,这个buffer会被释放
3、操作
#练习
getvalue()获取全部内容,和文件指针没有关系
from io import StringIO
sio = StringIO()
print(sio.readable(),sio.writable(),sio.seekable())
sio.write(‘abc\n123′)
sio.seek(0)
print(sio.readline())
print(sio.getvalue()) #无视指针,输出全部的内容
sio.close()
#输出结果
True True True
abc

abc
123
4、好处
一般来说,磁盘的操作比内存的操作要慢得多,内存足够的情况下,一般优化思路是少落地,减少磁盘IO的过程,可以大大提高程序的运行效率。
5、BytesIO
Io中模块的类
from io import BytesIO
内存中,开辟一个二进制模式的buffer,可以像文件对象一样操作。
当close方法被调用时候,buffer就会被释放。
#操作
from io import BytesIO
bio = BytesIO()
print(bio.readable(),bio.writable(),bio.seekable())
bio.write(b’abc\n123′)
bio.seek(0)
print(bio.readable())
print(bio.getvalue())#无视指针,输出全部的内容
bio.close()
#打印到控制台
True True True
True
b’abc\n123’

6、file-like对象
类文件对象,可以像文件对象一样操作
Socket对象,输入输出对象(stdin,stdout)都是类文件对象。
from sys import stdout
#from sys import stdout
f = stdout
print(type(f))
f.write(‘abc’)
#打印到控制台
<class ‘ipykernel.iostream.OutStream’>
abc

四、路径操作
1、路径操作模块
2、3.4版本之前:
Os.path
3、基本操作:
from os import path
p = path.join(‘/etc’,’sysconfig’,’netwoek’)
print(type(p),p) #输出。<class ‘str’> /etc/sysconfig/netwoek
print(path.exists(p)) # 路径存在与否。False
print(path.split(p)) #输出(‘/etc/sysconfig’, ‘netwoek’)
print(path.abspath(‘.’)) #输出/home/python/wcl/projects/web
等价于path.abspath(‘ ’)
print(path.dirname(p)) #/etc/sysconfig
print(path.basename(p)) #netwoek
print(path.splitdrive(p)) #(”, ‘/etc/sysconfig/netwoek’)

##
from os import path
p1 = path.abspath(__file__)
print(p1,path.basename(p1))
while p1 != path.dirname(p1):
p1 = path.dirname(p1)
print(p1,path.basename(p1))

4、3.4版本开始,建议使用pathlib模块,提供path对象来操作,包括目录和文件。
5、pathlib模块
From pathlib import Path
6、目录操作
初始化:from pathlib import Path
p =Path() #输出格式。PosixPath(‘.’)
p =Path(‘a’,’b’,’c/d’) #输出格式PosixPath(‘a/b/c/d’)
p =Path(‘/etc’) #PosixPath(‘/etc’)
7、路径拼接和分解
1)操作符/
Path 对象/Path对象
Path 对象/字符串或者 字符串/Path对象
2)分解
Parts属性,可以返回路径中的每一个部分
3)Joinpath
Joinpath(*other)
#代码块
p = Path()
p = p/’a’ #PosixPath(‘a’)
p1 = ‘b’/p #PosixPath(‘b/a’)
p2 = Path(‘c’) #PosixPath(‘c’)
p3 = p2 /p1 #PosixPath(‘c/b/a’)
print(p3.parts) #(‘c’, ‘b’, ‘a’)

p3.joinpath(‘etc’,’int.d’,Path(‘.httpd’))

#PosixPath(‘c/b/a/etc/int.d/.httpd’)
4)获取路径
Str获取路径字符串。
Bytes获取路径字符串的bytes
p = Path(‘/etc’) #
print(str(p),bytes(p))
##/etc b’/etc’
5)父目录
Parent目录的逻辑就是父目录
Parents 父目录序列,索引0就是直接的父
取直接的父目录:p.parents[2] p.parent
取到根目录:
p = Path(‘/a/b/c/d’)
print(p.parent.parent)
p.absolute().parents[len(p.absolute().parents)-1]
print(len(p.absolute().parents))
p = Path(‘/a/b/c/d’)
print(p.parent.parent)
for x in p.parents:
print(x)
#/a/b
/a/b/c
/a/b
/a
/
6)name stem suffix suffixes with_suffix(suffix) with_name(name)
(1)name目录的最后一个部分
(2)Suffix目录中最后一个部分的拓展名
(3)Stem目录最后一个部分,没有后缀。
(4)Suffixes 返回多个扩展名列表。
(5)With_suffix(suffix)补充扩展名到路径尾部,返回新的路径,扩展名存在则无效。
(6)With_name(name)替换目录最后一个部分并返回一个新的路径。
p = Path(‘/etc/config/system/cf.config.gz’)
print(p.name) #cf.config.gz

print(p.suffix) #.gz

print(p.suffixes) #[‘.config’, ‘.gz’]

print(p.stem) #cf.config

print(p.with_name(‘cf.config’)) #/etc/config/system/cf.config

#代码:
p1 = Path(‘README’)
print(p.with_suffix(‘.txt’))
#输出:/etc/config/system/cf.config.txt
(7)cwd()返回当前工作目录
(8)Home()返回当前家目录
(9)is_dir()是否是目录,目录存在返回True.
(10)is_symlink()是否是软连接
(11)is_file()是否是普通文件,文件存在返回True
(12)is_socket()是否是socket文件
(13)is_block)device()是否是块设备。
(14)is_char_device()是否是字符设备
(15)is_absolute()是否是绝对路径
(16)resolve()返回一个新的路径,这个新的路径就是当前Path的绝对路径,如果是软连接则直接被解析
(17)absolute()也可以获取绝对路径,但是推荐使用resolve()
(18)exists()目录或文件是否存在
(19)rmdir()删除空目录,没有提供判断目录为空的方法。
(20)touch(mode=0o666,exist_ok=True)创建一个文件
(21)as_uri()将文件路径返回URI。
(22)mkdir(mode=0o777,parents=False,exist_ok=False)
(23)Parents,是否创建父目录,True等同于mkdir-p:False时,父目录不存在,则抛出fileNotfounderror。
(24)exist_ok参数,在3.5版本加入,flase时路径存在,抛出异常,True时候异常被忽略。
(25)Iterdir()
迭代当前目录:
P = Path()
p = Path()
p /= ‘a/b/c/d’
p.exists()
p = Path()
p /=’a/b/c/d’
p.exists()

p.mkdir()
p.mkdir(parents=True)
p.exists()
p.mkdir(parents=True)
p.mkdir(parents=True,exist_ok=True)
p /=’readme.txt’
p.parent.rmdir()
p.aprent.exists()
p.mkdir()
p.mkdir(marents=True)

for x in p.parents[len(p.parents)-1].iterdir():
print(x,end=’\t’)
if x.is_dir():
flag = False
for _ in x.iterdir():
flag = True
break

print(‘dir’,’Not Empty’ if flag else ‘Empyt’,sep=’\t’)
elif x.is_file():
print(‘file’)
else:
print(‘other file’)

操作符/

7)通配符:glob(pattern)
通配给定的模式。
rglob(pattern)通配给定的模式,递归目录。
返回一个生成器;
list(p.glob(‘test’)) #返回当前目录对象下的test开头的文件
list(p.glob(‘**/*.py’))#递归所有目录,等同于rglob
g = p.rglob(‘*.py’) #生成器
next(g)

8)匹配:match(pattern) **任意一级,通配符。
模式匹配,成功返回True。
Path(‘a/b.py’).math(‘*.py’) #True
Path(‘/a/b/c.py’).math(‘b/*.py’)#True
Path(‘/a/b/c.py’).math(‘a/*.py’) #False 因为a文件下找不到.Py文件
Path(‘/a/b/c.py’).math(‘a/*/*.py’)#True
Path(‘/a/b/c.py’).math(‘a/**/*.py’)#True
Path(‘/a/b/c.py’).math(‘**/*.py’)#True
9)Stat()相当于stat命令。
Lstat()同stat(),但如果是符号链接,则显示符号链接本身的文件信息
lstat()软连接命令,相当于软连接的。
##
from pathlib import Path
p = Path(‘test’)
p.stat()
p1 = Path(‘t’)
p1.stat()
p1.lstat()
10)文件操作
Open(mode=’r’,buffering=-1,encoding=None,errors=None,newline=None)
使用方法类似内建函数open,返回一个文件对象。
3.5增加的新函数
Read_bytes()
以’rb’读取路径相对文件,并返回二进制流。
Read_text(encoding=None,errors=None)
以’rt’ 方式读取路径对应文件,返回文本。
Path.write_bytes(data)
以’wb’方式写入数据到路径对应文件。
Write_text(data,encoding=None,errors=None)
以’wt’方式写入字符串到路径对应文件。
#p = Path(‘my_binary_file’)
p.write_bytes(b’Binary file contents’)
p.read_bytes()
#打印出b’Binary file contents’
#p = Path(‘my_text_file’)
p.write_text(‘Text file contents’)
p.read_text()
#打印出’Text file contents’
from pathlib import Path
p = Path(‘test.py’)
p.write_text(‘hello python’)
print(p.read_text())
with p.open()as f:
print(f.read(5))
##打印出hello python
hello

五、os模块
1、操作系统平台
属性方法 结果
Os.name Windows是nt,,linux是posix
Os.uname() *nix支持
Sys.platform Windows显示win32,linux显示linux
Os.listdir(‘o:/tmp’)
Os也有open、read、write等方法,但是太低级,建议使用内建函数。
Ln -s test t1建立一个软连接
Os.stat(path,*,dir_fd=None,follow_symlinks=True)
本质上调用的是linux的stat。
Path:路径的string或者byetes,或者fd文件描述符。
Follow_symlinks True 返回文本本身信息,False且如果是软连接则显示软连接的本身。

Os.chmod(path,mode,*,dir_fd=None,follow_syslinks=True)
Os.chmod(‘test’,0o777)
Os.chown(path,uid,gid)
改变文件的属组,属主,但是需要足够的权限。
2、shutil模块
到目前为止:文件拷贝:使用两个文件对象,源文件读取内容,写入目标文件中来完成拷贝过程。但是这样会丢失stat数据信息(权限等),复制的只是文件的内容,没办法复制权限等内容:
目录复制python提供了一个方便的库,shutil(高级文件操作)

3、Copy复制 权限和内容
1)Copyfileobj(fsrc,fdst[,length])
文件对象的复制,fsrc和fdst是open打开的文件对象,复制内容,fdst要求可写。Length指定表示了buffer的大小。
import shutil
src = ‘test.txt’
dest = ‘test1.txt’
with open(src) as f1:
with open(dest,’w+’) as f2:
shutil.copyfileobj(f1,f2)

#不能完成copy,原因是指针移动了。
import shutil

with open(‘test.txt’,’w+’)as f1:
f1.write(‘abc\n123’)
f1.flush()
with open(‘test1.txt’,’w+’)as f2:
shutil.copyfileobj(f1,f2)
#改正代码
import shutil

with open(‘test.txt’,’w+’)as f1:
f1.write(‘abc\n123’)
f1.flush()
f1.seek(0)
with open(‘test1.txt’,’w+’)as f2:
shutil.copyfileobj(f1,f2)
总结:copyfile(src,dest,*,follow_symlinks=True)
复制文件内容,不含元数据,sc、dst为文件的路径字符串。
本质上就是调用copyfileobj,所以不带元数据二进制内容复制。
2)copymode(src,dst,*,follow_symlinks=True)
仅仅复制的是权限。
shutil.copymode(‘test.txt’,’test1.txt’)

##显示权限等信息。
import shutil
import os

with open(‘test.txt’,’w+’)as f1:
f1.write(‘abc\n123’)
f1.flush()
f1.seek(0)
with open(‘test1.txt’,’w+’)as f2:
shutil.copyfileobj(f1,f2)
print(os.stat(‘test.txt’))
print(os.stat(‘test1.txt’))
##打印出;
os.stat_result(st_mode=33206, st_ino=42502721483335735, st_dev=4009623578, st_nlink=1, st_uid=0, st_gid=0, st_size=8, st_atime=1524639016, st_mtime=1524639778, st_ctime=1524639016)
os.stat_result(st_mode=33206, st_ino=1407374883584914, st_dev=4009623578, st_nlink=1, st_uid=0, st_gid=0, st_size=8, st_atime=1524639016, st_mtime=1524639778, st_ctime=1524639016)
3)copystat(src,dst,*,follow_symlinks=True)
##shutil.copystat(f1,f2)复制元数据,stat包括权限。
4)总结。复制文件内容,权限和部分元数据,不包括创建时间和修改时间。本质上是调用。
copyfile(src, dst, follow_symlinks=follow_symlinks)
copymode(src, dst, follow_symlinks=follow_symlinks)
4、Copy2 stat 和内容。 比copy多了复制全部元数据,需要平台的支持。
本质上调用了。
copyfile(src, dst, follow_symlinks=follow_symlinks)
copystat(src, dst, follow_symlinks=follow_symlinks)
5、Copytree 递归复制目录。
Copytree(src,dst,symlinks=Flase,ignore=None,copy_function=copy2,ignore_dangling_symlinks=False).递归复制的目录,默认使用copy2,也就是带更多的元数据复制。
Src 、dst必须是目录,src必须存在,dst必须不存在,提供一个callable(src,names)-》ignore_names.提供一个函数,他就会被调用。Src是源目录,names是os.listdir(src)的结果,就是列出src中的文件名称,返回值是要被过滤的文件名的set类型。
Src dst 必须为目录。

6、rm删除
Shutil.rmtree(path,ignore_errors=False,onerrors=None)
递归删除,如同rm-fd一样危险,慎用。
不是原子操作,有可能删除操作,就会中断,已经删除的就是已经删除了。
Ignore_error为True,忽略错误,当为False或者omitted时候oneerrors生效。
Oneerror刷为callable,接受函数function、path和execinfo。
Shutil.rmtree(‘test’)
7、move移动
Move(src,dst,copy_function=copy2)
递归移动文件、目录到目标,返回目标。本身使用的是os.rename方法。
如果不支持rename,如果是目录则想copytree在删除源目录。
默认使用copy2方法
Shutil还有打包功能,生成tar并压缩,支持,zip、gz、bz、xz。
六、csv文件

1、csv文件简介:

逗号分隔符Comma—Separated Values。

Csv是一个被行分隔符、列分隔符划分为行和列的文本文件。

Csv不指定字符编码。

 

行分隔符为\r\n,最后一样可以没有换行符。

列分隔符常为逗号或者制表符。

每一行称为一条记录record。

字段可以使用双引号括起来,也可以不使用。如果字段中出现了双引号,逗号,换行符必须使用双引号括起来。如果字段的值是双引号,使用两个双引号表示一个转义。

2、手动生成csv文件。

代码:

from pathlib import Path

p = Path(‘test.csv’)
parent = p.parent
if not parent.exists():
parent.makdir( parents =True)

csv_body = ”’\
id,name,age,comment
1,zs,18,”im 18″
2,ls,20,”this is a test string”
3,ww,23,”nihao

jisuanji

”’
p.write_text(csv_body)

id name age comment    
1 zs 18 im 18    
2 ls 20 this is a test string    
3 ww 23 nihao

jisuanji

   
           

 

表头可选,和字段列对齐就行啦

\须行符。

3、csv模块

reader(csvfile,dialect=’excel’,**fmtparams)

返回DictReader对象,是一个行迭代器。

delimiter列分隔符,逗号

lineterminator行分隔符\r\n

quotechar字段的引用符号,缺省为”,双引号。

 

双引号的处理:

doublequote双引号的处理,默认为True,如果和quotechar为同一个,True则使用两个双引号表示,False表示使用转义字符将作为双引号的前缀。

escapechar一个转义字符,默认为None。

quoting指的双引号的规则,QUOTE_ALL所有字段;QUOTE_MINIMAL特殊字符字段;

QUOTE_NONNUMERIC非数字字段;QUOTE_NONE都不使用引号。

 

writer(csvfile,dialect=’excel’,**fmtparams)

返回Dictwriter实例。

主要方法有writerow、writerows。

Writerow(iterable)

##

import csv
p = Path(‘test.csv’)
parent = p.parent
if not parent.exists():
parent.makdir( parents =True)

with open(str(p))as f:
reader = csv.reader(f)
print(next(reader))
print(next(reader))

rows = [
[4,’tom’,22,’tom’],
(5,’jerry’,24,’jerry’),
(6,’justin’,22,’just\nin’),
“abcdefghi”,
((1,),(2,))
]
row =rows[0]

with open(str(p),’w+’)as f:
writer = csv.writer(f)
writer.writerow(row)
writer.writerows(rows)

from pathlib import Path

p = Path(‘test.csv’)
parent = p.parent
if not parent.exists():
parent.makdir( parents =True)

csv_body = ”’\
id,name,age,comment
1,zs,18,”im 18″
2,ls,20,”this is a test string”
3,ww,23,”nihao

jisuanji

”’
import csv
p.parent.mkdir(parents=True,exist_ok=True)
p.write_text(csv_body)

rows = [
[‘4′,’tom’,’16’,’jerry’],
[‘5′,’zs’,’18’,’12’],
[‘6′,’ls’,’20’,’this is ‘],
[‘7′,’ww’,’14’,’hello’],
(1,2,3),
[(1,2,3),(1,2,3)]
]
row = rows[0]
#p = Path(csvname)
if p.is_file():
with open(str(p),’a’,newline=”)as f:
writer = csv.writer(f)
writer.writerow(row)
writer.writerows(rows)

4、ini文件处理;

作为配置文件,ini文件格式很流行。

 

中括号加唯一的名称,名称不得重复。中括号里面的部分称为section,译作节、区、段。

每一个section内,都是key=value行程的键值对,可以称为option选项。

 

注意DEFAULT是缺省section的名字,必须大写。

一为缺省区。

中括号里面的部分成为section,译作节,区、段。

每个section内,都是key,value键值对,key成为option选项。

Default是缺省section,必须大写。

5、Configparser模块。

函数或者类后面加括号,调用。

Configparser 模块的ConfigParser类就是用来操作。

可以将section当做key,section存储着键值对形成字典,可以吧ini配置文件当做一个嵌套的字典,默认使用的是有序字典。

read(filenames,encoding=None)

读取ini文件,可以是单个文件,也可以是文件列表,可以指定文件编码。

Sections()返回section列表,缺省section不包括在内。

add_aection(section_name)增加一个section.

Has_section(section_name)判断section是否存在。

options(section)返回section的所有option,会追加缺省section的option

has_option(section,option)判断section是否存在这个option

get(section,option,*,raw=False,vars=None[,fallback])

从指定的段的选项上取值,如果找到就返回,没找到就去DEFAULTT段找有没有。

getint(section,option,*,raw=False,Vars=None[,fallback])

getfloat(section,option,*,raw=False,vars=None[,fallback])

getboolean(section,option,*,raw=False,vars=None[,fallback])

三个方法和get一样,返回指定的数据。

Items(raw=False,vars=None)

Items(section,raw=False,vars=None)

没有section,则返回section名字及其对象,如果指定section,则返回这个指定的键值对组成的二元组。

Set(section,option,value)

Sextion存在的情况下,写入option=value,要求option,value必须是字符串。

Remove_section(section)

移除section及其所有的option

Remove_option(section,option)

移除section下的option。

Write(fileobject,space_around_delimiters=True)

将当前的config的所有内容写入到fileobject中,一般open函数使用w模式。

from configparser import ConfigParser

filename = ‘test.ini’
newfilename = ‘mysql.ini’

cfg = ConfigParser()
cfg.read(filename)
print(cfg.sections())
print(cfg.has_section(‘client’))

print(cfg.items(‘mysqld’))
for k,v in cfg.items():
print(k,type(k))
print(k,cfg.items(k))

tmp = cfg.get(‘mysql’,’port’)
print(type(tmp),tmp)
print(cfg.get(‘mysql’,’a’))
print(cfg.get(‘mysqld’,’magedu’,fallback=’python’))

tmp =cfg.getint(‘mysql’,’port’)
print(type(tmp),tmp)

if cfg.has_section(‘test’):
cfg.remove_option(‘test’)
cfg.add_section(‘test’)
cfg.set(‘test’,’test1′,’1′)
cfg.set(‘test’,’test2′,’2′)

with open(newline,’w’) as f:
cfg.write(f)

print(cfg.getint(‘test’,’test2′))

cfg.remove_option(‘test’,’test2′)

print(‘x’in cfg[‘test’])
print(‘x’in cfg[‘test2′])
print(cfg._dict)

with open(newline,’w’)as f:
cfg.write(f)

七、序列化和反序列化

为什么要序列化

内存中的字典、列表、集合以及各种对象,如何保存到一个文件中。

设计一套协议,按照某种规则,吧内存中的数据保存到文件中,文件是一个个字节序列。所以必须把数据额转换为字节序列,输出到文件,这就是序列化,反之,从文件的字节 序列恢复到内存中,就是反序列化。

1、定义:

Serialization系列化,将内存中对象存储下来,把他变成一个个字节。二进制。

deSerialization反序列化,将文件的一个个字节到内存中。

序列胡保存到文件就是持久化。

可将数据序列化后持久化,或者网络传输,也可以将文件中或者网络接受到的字节序列反序列化。

2、pickle库:

Python中的序列化、反序列化模块

dumps对象序列化为bytes对象

dump对象序列化到文件对象,就是存入到文件。

loads从bytes对象反序列化。

load对象反序列化,从文件读取数据.

##

import pickle
filename = ‘ser’
x= ‘a’
y = ‘100’
z = ‘100’

with open(filename,’wb’) as f:
pickle.dump(x,f)
pickle.dump(y,f)
pickle.dump(z,f)

with open(filename,’rb’)as f:
for _ in range(3):
a = pickle.load(f)
print(a,type(a))

还原的时候不一定是完全一样的。

序列化应用:一般来说,本地序列化的情况,应用较少,大多数都是用在网络传输上面的。

将数据额序列化后通过网络传输到远程节点,远程服务器上的服务将接受到的数据反序列化后,就可以使用了。

但是,要注意的是,远程接收端,反序列化时候必须有对应的数据类型,否则就会报错。尤其是自己定义的类。必须远程得有一致的定义。

3、Json

1)是一种轻量级的数据交换格式,基于ECMAScript(w3c制定的JS规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。

2)数据类型

双引号引起来的字符串,数值,true和flase,null,对象,数组,这些都是值。

字符串

由双引号包围起来的任意字符的组合,可以有转义字符。

数值:有正负,整数,浮点数。

对象:无序的键值对的集合。

格式:{key1:value1,…..keyn:valuen}

Key必须是一个字符串,需要双引号包围这个字符。

Value可以是任意合法的值。

 

数组 :有序的值的集合

格式:[value1,….valuen]

 

 

例子:

3)json模块

Python与json

Python支持少量内建数据类型到json类型的转换。

Python类型 Json类型
True True
False False
None Null
Str String
Int Integer
Float Float
List Array
Dict obiect

4)常用的方法

Python 类型 Json类型
Dumps Json编码
Dump Json编码并写入文件
Loads Json解码
Load Json解码,从文件读取数据

 

import json
d = {‘name’:’tom’,’age’:20,’interest’:[‘music’,’movie’]}
j = json.dumps(d)
print(j)

d1 = json.loads(j)
print(d1)

{“name”: “tom”, “age”: 20, “interest”: [“music”, “movie”]}

{‘name’: ‘tom’, ‘age’: 20, ‘interest’: [‘music’, ‘movie’]}

 

一般json编码的数据就很少落地,数据都是通过网络传输。传输的时候要考虑压缩。

本质上来说就是一个文本,就是个字符串。

Json很简单,几乎语言编程都支持json,所以应用范围十分广泛。

4、MessagePack

是一个基于二进制高效的对象化序列类库,可用于跨语言通信。

可以像json那样,在许多种需要之间交换结构对象。

比json更快速也更轻巧。

支持python,ruby,java,C/C++等众多语言。

图片1图片2

 

安装:

Pip install msgpack-python

常用方法

Packb序列化对象,提供了dumps兼容pickle和json

Unpackb反序列化对象,提供了loads来兼容

Pack序列化对象保存到文件对象,提供了dump来兼容

Unpack反序列化对象保存到文件对象,提供了load来兼容。

##

import json
import msgpack

d = {‘person’:[{‘name’:’tom’,’age’:18},{‘name’:’jerry’,’age’:16}],’total’:2}

j = json.dumps(d)
m =msgpack.dumps(d)

print(‘json={},msgpack={}’.format(len(j),len(m)))
print(j.encode(),len(j.encode()))
print(m)

u = msgpack.unpackb(m)
print(type(u),u)

u = msgpack.unpackb(m,encoding=’utf-8′)
print(type(u),u)

MessagePack简单易用,高效压缩,支持的语言丰富

序列化也是一种很好的选择。

 

简单易用,高效压缩,支持语言丰富,所以,用它序列化是一种很好的选择。

习题1.将一个ini文件转换为json文件

思路:1)首先导入configparser库和json库。

2)返回一个configparser对象。)

3)创建一个字典,找到sections。

4)字典的k,v在对象的items里面,最后返回一个字典,

5)利用dumps把字典写入到新文件中。

import configparser
import json

filename = ‘test.ini’
jsonname = ‘test1.json’
cfg = configparser.ConfigParser()
cfg.read(filename)

sections = cfg.sections()

d = {}
for k,v in cfg.items():
d[k] = dict(cfg.items(k))
print(d)
json.dump(d,open(‘test1.json’,’w’))

习题2、统计单词次数

#第一次代码:

chars = set(r”””!#$%^&*()[]”‘:-=+_~\|/.,""")
def make_key(x):

lst = []
key = x.lower()
for  c in key:
if c in chars:
lst.append('')
else:
lst.append(c)
return ''.join(lst).split()

with open('sample.txt',encoding='utf-8')as f:
d = {}
not_words = ['of', 'the', 'a']
for line in f:
words = line.split()
for wordlist in map(make_key,make_words):
for word in wordlist:
if word not in not_words:
d[word] = d.get(word,0)+1

print(sorted(d.items(),key=lambda item:item[1],reverse=True))

1)先判断字符,定义一个函数,把特殊字符作为一个set,遇到特殊字符跳过,打标记,

然后最后一次次切片。

2)定义一个统计单词出现次数的函数,利用字典。也就是字典遍历。遍历后,最后返回一个字典。

3)排序,利用sorted函数,指定函数,打印出排行多少位的。

def makekey2(line,chars=set(r"""!#$%^&*()[]"':-=+_~\|/.,”””)):
start = 0

for i,c in enumerate(line):
if c in chars:
if start == i: #如果紧挨着还是特殊字符,start一定是等于i
start += 1  #加1 并continue
continue
yield line[start:i]
start = i + 1     #加1 是跳过这个不需要的字符c

else:
if start < len(line):  #小于,说明还有有效的字符,而且一直到末尾。
yield line[start:]

def wordcount(filename,encoding=’utf-8′,ignore=set()):
d = {}
with open(filename,encoding=encoding)as f:
for line in f:
for word in map(str.lower,makekey2(line)):
if word not in ignore:
d[word] = d.get(word,0)+1
return d

def top(d,n=10):
for i,(k,v) in enumerate(sorted(d.items(),key=lambda  item:item[1],reverse=True)):
if i>n:
break
print(k,v)
top(wordcount(‘sample.txt’,ignore={‘the’,’a’}))

5、argparse模块

1)一个可执行文件或者脚本都可以接收参数。

ls -l/etc    /etc是位置参数    -l 是短选项

如何将参数传递到程序,就使用参数分析模块argparse

2)参数分类。

参数分为:位置参数,参数放在哪里,就要对应一个参数位置,例如/etc 就是对应的一个参数位置。

选项参数,必须通过前面 – 的短选项或者 –的长选项,然后后面的才算是参数,短选项后面也可以没有参数。

/etc 对应的就是位置参数, -l是选项参数。

3)基本解析

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
parser.print_help()

 

usage: argparse模块使用.py [-h]

 

optional arguments:

-h, –help  show this help message and exit

Argparse不仅仅做了参数的定义和解析,还自动生成了帮助信息。Usage,可以看到现在定义的参数是否是自己想要的。

4)解析器的参数

参数名称 说明
Prog 程序的名字,缺省使用,sys.argv[0]
add_help 自动生成解析器增加 – h和–help选项,默认为True
description 为程序添加功能描述

import argparse

parser = argparse.ArgumentParser(prog= ‘ls’,add_help=True,description=’list directorycontents’)
args = parser.parse_args()
parser.print_help()

 

usage: ls [-h]

 

list directorycontents

 

optional arguments:

-h, –help  show this help message and exit

5)位置参数解析器

ls 基本功能解决目录内容的打印。

打印的时候应该制定目录路径,需要的位置参数。

import argparse

parser = argparse.ArgumentParser(prog= ‘ls’,add_help=True,description=’list directorycontents’)
parser.add_argument(‘path’)
args = parser.parse_args()  #分析参数
parser.print_help()      #打印帮助

 

usage: ls [-h] path

ls: error: the following arguments are required: path

 

程序等定义为

ls [-h] path

-h为帮助,可有可无

path  为位置参数,必须提供。

 

6)传参

Parse_args(args=None,namespace=None)

args参数列表,一个可迭代对象,内部会把可迭代对象转换成list,如果为None则使用命令行传入参数,非None则使用args参数的可迭代对象。

 

import argparse

parser = argparse.ArgumentParser(prog= ‘ls’,add_help=True,description=’list directorycontents’)
parser.add_argument(‘path’)   #位置参数
args = parser.parse_args((‘/etc’,))  #分析参数
print(args)      #打印名词空间中收集的参数
parser.print_help()      #打印帮助

 

Namespace(path=’/etc’)

usage: ls [-h] path

 

list directorycontents

 

positional arguments:

path

 

optional arguments:

-h, –help  show this help message and exit

 

Namespace(path=’/etc’)里面的path参数存储在一个Namespace对象内的属性上,,可以通过Namespace对象属相来访问。args.path

 

7)非必须位置参数。

必须输入位置参数,否则会报错。

有些时候ls命令不需要输入任何路径就表示列出当前目录的文件列表。

 

import argparse

parser = argparse.ArgumentParser(prog= ‘ls’,add_help=True,description=’list directorycontents’)
parser.add_argument(‘path’,nargs=’?’,default=’.’,help=’path help’)   #位置参数,可有,可无,缺省值,帮助
args = parser.parse_args()  #分析参数
print(args)      #打印名词空间中收集的参数
parser.print_help()      #打印帮助

 

 

Namespace(path=’.’)

usage: ls [-h] [path]

 

list directorycontents

 

positional arguments:

path        path help

 

optional arguments:

-h, –help  show this help message and exit

 

看到path也变成了可选位置参数,没有提供默认值.表示当前的路径。

.help表示帮助文档中这个参数的描述。

.nargs表示这个参数接受结果参数,?表示可有可无,+表示至少一个,*表示任意个,数字表示必须是制定数目个。

.default表示如果不提供该参数,就一直使用这个值,一般和?、*配合,因为他们都可以不提供位置参数,不提供就是使用缺省值。

8)选项参数

-l 的实现:

-a 的实现。长选项同时给出,

 

import argparse

parser = argparse.ArgumentParser(prog= ‘ls’,add_help=True,description=’list directorycontents’)
parser.add_argument(‘path’,nargs=’?’,default=’.’,help=’path help’)   #位置参数,可有,可无,缺省值,帮助
parser.add_argument(‘-l’,action =’store_true’,help = ‘use a one listing format’)
parser.add_argument(‘-a’,’–all’,action =’store_true’,help=’show all files,do not ignore entries starting with .’)
args = parser.parse_args()  #分析参数
print(args)      #打印名词空间中收集的参数
parser.print_help()      #打印帮助

 

Namespace(all=False, l=False, path=’.’)

usage: ls [-h] [-l] [-a] [path]

 

list directorycontents

 

positional arguments:

path        path help

 

optional arguments:

-h, –help  show this help message and exit

-l          use a one listing format

-a, –all   show all files,do not ignore entries starting with .

 

  • ls 业务功能的实现。

上面解决了参数的定义和传参的问题,下面解决业务问题:

  • .列出所有指定路径的文件,默认是不递归的。
  • -a显示所有文件,包括隐藏文件。
  • -l详细列表模式显示。

代码实现:listdirdetail和listdir

 

import argparse
from pathlib import Path
from datetime import datetime

#获得一个参数解析器
parser = argparse.ArgumentParser(prog= ‘ls’,add_help=True,description=’list directorycontents’)
parser.add_argument(‘path’,nargs=’?’,default=’.’,help=’path help’)   #位置参数,可有,可无,缺省值,帮助
parser.add_argument(‘-l’,action =’store_true’,help = ‘use a one listing format’)
parser.add_argument(‘-a’,’–all’,action =’store_true’,help=’show all files,do not ignore entries starting with .’)
args = parser.parse_args()  #分析参数
print(args)      #打印名词空间中收集的参数
parser.print_help()      #打印帮助

def listdir(path,all=False):

p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith(‘.’):  #不显示隐藏文件
continue
yield  i.name

print(list(listdir(args.path)))

#获取文件类型
def _getfiletype(f:path):
# f = Path(path)
if f.is_dir():
return ‘d’
elif f.is_block_device():
return ‘b’
elif f.is_char_device():
return ‘c’
elif f.is_socket():
return ‘s’
elif f.is_symlink():
return ‘l’
else:
return ‘-‘
##显示文件权限等  mode

modelist = dict(zip(range(9),[‘r’,’w’,’x’,’r’,’w’,’x’,’r’,’w’,’x’]))
def _getmodestr(mode:int):
m = mode &0o777
mstr = ”
for i in range(8,-1,-1):
if m >>i & 1:
mstr += modelist[8-i]
else:
mstr +=’-‘
return mstr

def listdirdetail(path,all=False,detail=False):

p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith(‘.’):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t  = _setfiletype(i)
mode = _getfiletype(i)+_getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime(‘%Y %m %d %H:%M:%S’)
yield (mode,stat.st_nlink,stat.st_uid,stat.st_gid,stat.st_size,atime,i.name)

for x in listdir(args.path):
print(x)

 

Mode是整数,八进制描述的权限,最终显示rwx的格式。

 

modelist = dict(zip(range(9),[‘r’,’w’,’x’,’r’,’w’,’x’,’r’,’w’,’x’]))
def _getmodestr(mode:int):
m = mode &0o777
mstr = ”
for i in range(8,-1,-1):
if m >>i & 1:
mstr += modelist[8-i]
else:
mstr +=’-‘
return mstr

9)排序

显示的文件按照文件名的升序排序输出。

Sorted(listdir(args.path,detail=True),key=lambda x:x[len(x)-1])

10)完整代码:

import argparse
from pathlib import Path
from datetime import datetime

#获得一个参数解析器
parser = argparse.ArgumentParser(prog= ‘ls’,add_help=True,description=’list directorycontents’)
parser.add_argument(‘path’,nargs=’?’,default=’.’,help=’path help’)   #位置参数,可有,可无,缺省值,帮助
parser.add_argument(‘-l’,action =’store_true’,help = ‘use a one listing format’)
parser.add_argument(‘-a’,’–all’,action =’store_true’,help=’show all files,do not ignore entries starting with .’)

def listdir(path,all=False,detail=False):
def _getfiletype(f: path):
if f.is_dir():
return ‘d’
elif f.is_block_device():
return ‘b’
elif f.is_char_device():
return ‘c’
elif f.is_socket():
return ‘s’
elif f.is_symlink():
return ‘l’
else:
return ‘-‘

modelist = dict(zip(range(9), [‘r’, ‘w’, ‘x’, ‘r’, ‘w’, ‘x’, ‘r’, ‘w’, ‘x’]))

def _getmodestr(mode: int):
m = mode & 0o777
mstr = ”
for i in range(8, -1, -1):
if m >> i & 1:
mstr += modelist[8 – i]
else:
mstr += ‘-‘
return mstr

def _listdir(path, all=False, detail=False):

p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith(‘.’):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t  = _setfiletype(i)
mode = _getfiletype(i) + _getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime(‘%Y %m %d %H:%M:%S’)
yield (mode, stat.st_nlink, stat.st_uid, stat.st_gid, stat.st_size, atime, i.name)

yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) – 1])

if __name__ == ‘__main__’:
args = parser.parse_args()  # 分析参数
print(args)  # 打印名词空间中收集的参数
parser.print_help()  # 打印帮助
files = listdir(args.path,args.all,args.l)

11)-h的实现

-h ,-human-readable,如果-l存在,-h有效。

 

import argparse
from pathlib import Path
from datetime import datetime

parser = argparse.ArgumentParser(prog=’ls’,description=’list directory contents’,add_help=False)
parser.add_argument(‘path’,nargs=’?’,default=’.’,help=’path help’)
parser.add_argument(‘-h’,’–human-readable’,action=’store_true’,help=’with -l,print sizes in human readable format’)
# args = parser.parse_args()  # 分析参数
# print(args)  # 打印名词空间中收集的参数
# parser.print_help()  # 打印帮助

def listdir(path,all=False,detail=False,human=False):
def _getfiletype(f:path):
“””获取文件的类型”””
        if f.is_dir():
return ‘d’
elif f.is_block_device():
return ‘b’
elif f.is_char_device():
return ‘c’
elif f.is_socket():
return ‘s’
elif f.is_symlink():
return ‘l’
elif f.is_fifo():
return ‘p’
else:
return ‘-‘

modelist = dict(zip(range(9),[‘r’, ‘w’, ‘x’, ‘r’, ‘w’, ‘x’, ‘r’, ‘w’, ‘x’]))

def _getmodest(mode:int):
m =mode & 0o777
mstr = ”
for x in range(8,-1,-1):
if m >> i & 1:
mstr += modelist[8-i]
else:
mstr += ‘-‘
return mstr

def _gethuman(size: int):
units = ‘KMGTP’
depth = 0
while size >= 1000:
size = size // 1000
depth += 1
return ‘{}{}’.format(size, units[depth])

def _listdir(path,all=False,detail=False,human=False):
p =Path(path)
for i in p.iterdir():
if not all and i.name.startswith(‘.’):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t  = _setfiletype(i)
mode = _getfiletype(i) + _getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime(‘%Y %m %d %H:%M:%S’)
yield (mode, stat.st_nlink, stat.st_uid, stat.st_gid, stat.st_size, atime, i.name)

yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) – 1])

if __name__ == ‘__main__’:
args = parser.parse_args()  # 分析参数
print(args)  # 打印名词空间中收集的参数
parser.print_help()  # 打印帮助
files = listdir(args.path,args.all,args.l)

12)改进mode的模块

使用stat模块

import stat

from pathlib import Path

stat.filemode(Path().stat().st_mode)

13)最终代码:

import argparse
import stat
from pathlib import Path
from datetime import datetime

parser = argparse.ArgumentParser(prog=’ls’,description=’list directory contents’,add_help=False)
parser.add_argument(‘path’,nargs=’?’,default=’.’,help=’path help’)
parser.add_argument(‘-h’,’–human-readable’,action=’store_true’,help=’with -l,print sizes in human readable format’)
parser.add_argument(‘-l’,action =’store_true’,help = ‘use a one listing format’)
parser.add_argument(‘-a’,’–all’,action =’store_true’,help=’show all files,do not ignore entries starting with .’)
# args = parser.parse_args()  # 分析参数
# print(args)  # 打印名词空间中收集的参数
# parser.print_help()  # 打印帮助

def listdir(path,all=False,detail=False,human=False):
def _gethuman(size: int):
units = ‘KMGTP’
depth = 0
while size >= 1000:
size = size // 1000
depth += 1
return ‘{}{}’.format(size, units[depth])

def _listdir(path, all=False, detail=False, human=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith(‘.’):
continue
if not detail:
yield (i.name,)
else:
st = i.stat()
# t  = _setfiletype(i)
mode = stat.filemode(st.st_mode)
atime = datetime.fromtimestamp(st.st_atime).strptime(‘%Y %m %d %H:%M:%S’)
size = str(st.st_size) if not huam else _gethuman(st.st_size)
yield (mode, st.st_nlink, st.st_uid, st.st_gid, size, atime, i.name)

yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) – 1])

if __name__ == ‘__main__’:
args = parser.parse_args()  # 分析参数
print(args)  # 打印名词空间中收集的参数
parser.print_help()  # 打印帮助
files = listdir(args.path, args.all, args.l)

八、正则表达式:
1、概述:
Regular Expression。缩写regex,regexp,R等:
正则表达式是文本处理极为重要的工具。用它可以对字符串按照某种规则进行检索,替换。
Shell编程和高级编程语言中都支持正则表达式。
2、分类:
BRE:基本正则表达式,grep、sed、vi等软件支持,vim有扩展。
ERE:扩展正则表达式,egrep(grep-E)、sed-r。
PCRE: re模块。Python中。几乎所有高级语言都是PCRE的方言或者变种。
3、基本语法
1)元字符
代码 说明 举例
. 匹配除换行符外任意一个字符 .
[abc] 字符集合,只能表示一个字符位置。匹配所包含的任意一个字符 [abc]匹配plain中的’a’
[^abc] 字符集合,只能表示一个字符位置,匹配除去集合内字符的任意一个字符。 [^abc]可以匹配plain中’p’,’l’,’i’或者’n’
[a-z] 字符范围,也是个集合,表示一个字符位置,匹配所包含的任意一个字符。 [a-d]可以匹配plain中的’a’

[^a-z] 字符范围,也是个集合,表示一个字符位置,匹配除去集合内字符的任意一个字符。 [a-d]可以匹配plain的中’p’,’l’,’i’或者’n’

\b 匹配单词的边界 \ba在文本中找到单词a开头的,a\b找到以a结尾的。
\B 不匹配单词的边界 t\B包含t的单词但是不以t结尾,write
\Bb不以b开头但是包含b的单词,able
\d [0-9]匹配1位数字 \d
\D [^0-9]匹配一位非数字
\w 匹配[a-zA-Z0-9],包括中文的字 \w
\W 匹配\w之外的字符。
\s 匹配1位空白字符,包括换行符,制表符、空格[\f\r\n\t\v]
\S 匹配非空白字符。
2)转义
凡是在正则表达式中有特殊意义的符号,如果想使用它他的本意,使用\转义,反斜杠自身,得使用\\ \r 转义后代表回车 \n 换行
3)重复
代码 说明 举例
* 表示前面的正则表达式会重复0次或者多次 e\w*单词e中可以有非空白字符
+ 表示前面的正则表达式重复至少1次 e\w+单词e后面至少有一个非空白字符。
? 表示前面的正则表达式会重复0次或者1次 e\w?单词e后面至多有一个非空白字符
{n} 重复固定的n次 e \w{1}单词中e后面只能有一个非白字符
{n,} 重复至少n次 e \w{1,} >>>e\w+
e\w{0,}>>>e\w*
e \w{0,1}>>>e\w?
{n,m} 重复n到m次 e \w{1,10}单词后面至少一个,至多10个非空白字符。
5、基本练习:
1)匹配手机号码:
\d{11,}
2)匹配中国座机:
\d{3,4}-\d{7,8}
3)源代码
代码 说明 举例
x | y 匹配x或者y Wood took foot food
使用w|food 或者(w|f)odd
捕获
(pattern) 使用小括号指定一个字表达式,也叫分组捕获后会自动分配组号从1开始,可以改变优先级
\数字 匹配对应的分组 (very)\1匹配very very,但捕获的组group是very。
(?:pattern) 如果仅仅为了改变优先级,就不需要捕获分组 (?:w|f)ood ‘industr(?:y|lies)’等价于’industry|industries’
(?<name>exp)(?’name’exp) 分组捕获,但是可以通过name访问分组。Python的语法必须是(?P<name>exp)
零宽断言
(?=exp) 零宽度正测先行断言:
断言exp一定在匹配的右边出现,也就是说断言后面一定跟个exp f(?=00)f后面一定有oo出现
(?<=exp) 零宽度正回顾后发断言:
断言exp一定出现在匹配的左边出现。也就是说前面一定有个exp前缀 (?<=f)ood,(?<=t)ook分别匹配ood,ook,ook前面一定有t出现。
负向零宽断言
(?!exp) 零宽度负预测先行断言;
断言一定不会出现在右侧,也就是说断言后面一定不是exp \d{3}(?!\d)匹配三位数字,断言三位数字后面一定不能是数字
(?<!exp) 零宽度负回顾后发断言
断言exp一定不能出现在左侧,也就是说断言前面一定不能是exp (?<!f)ood ood 的左边一定不是f
注释
(?#comment) 注释
断言不占分组号,断言如同条件,只是要求匹配必须满足断言条件。
分组和捕获是同一个意思;
使用正则表达式时候,能用简单表达式,就不要复杂的表达式。
4)贪婪与非贪婪;
代码 说明 举例
*? 匹配任意次,但是尽可能少重复 *?尽可能的少,可以是没有。

+? 匹配至少1次,但是尽可能少重复 +?至少一次。

?? 匹配0次或者1次,尽可能少重复 ??尽可能的少,至少0次。

{n,}? 匹配至少n次,尽可能没有
{n,m} 至少匹配n次,至多m次,尽可能少重复
Very very very happy V.*y 和v.*?y
5)引擎选项:
代码 说明 Python中
ignoreCase 匹配时忽略大小写 re.l re.lGNORECASE
Singleline 单行模式,可以匹配所有字符,包括\n re.S re.DOTALL
Multine 多行模式^,行首,$行尾 re.M re.MULTLINE
lgnorePatternWhites 忽略表达式中的空白字符,如果要使用空白字符转义,#可以用来做注释 re.x
re.VERBOSE
6)总结:
单行模式;
.可以匹配所有字符,包括换行符
^表示整个字符串的开头,$整个字符串的结尾。
多行模式:
.可以匹配除了换行符之外的字符。
^表示整个字符串的开头,$整个字符串的结尾。
^表示整个字符串的开始,$表示整个字符串的结尾。开始指的是\n紧接着下一个字符,结束指的是/n前的字符。
可以认为,单行模式就如同看穿了换行符,所有文本就是一个长长的只有一行的字符串,所有^表示整个字符串的开头,$整个字符串的结尾。
多行模式,注意字符串看不见的换行符,\r\n 会影响e$测试,e$只能匹配e\n.

*重复任意次 限制的话用*? 得到了限制。
默认是贪婪模式,也就是尽量多匹配长的字符串。
7)练习题:
匹配一个0-9999之间的任意数字:
^([1-9]?\d\d?|\d)(?!\d)
匹配合法的ip地址:
(\d{1,3}\.){3}\d{1,3}
192.168.1.150
0.0.0.0
255.255.255.255
17.16.52.100
172.16.0.100
400.400.999.888
001.022.003.000
257.257.255.256

ip的验证采用python 的socket模块.
选出含有ftp的链接。且文件的类型是gz或者xz的。
.*ftp.*/([^/]*\.(?:gz|xz))
6、python的正则表达式
1)常量:r.M(re.MULTILINE)多行 r.S(re.DOTALL)单行。 r.L(re.IGNORECASE)忽略大小写。 r.X(re.VERBOSE)忽略空白字符。 使用|或运算
2)方法、编译:
re.compile(pattern,flags=0)
设定flag,编译模式。返回曾泽表达式对象regex。
Pattern就是正则表达式的字符串,flags是选项,正则表达式需要被编译,为了提高效率,为了提高效率,这些编译后的结果就会被保存,下次使用同样的pattern的时候,就会不需要再次编译。
re的其他方法为了提高效率都调用了编译方法,就是为了提速。
3)Re.matth(pattern,string,flags=0)匹配只是做了单次的匹配。从头开始,从第一个字符串匹配上。对匹配字符串加上了一^字符。只是匹配了一次。
Regex.match编译后可以调整位置(切片)可以设置开始和结束的位置。返回match对象 regex = re.compile
match必须是以他开头的,指定索引。
4)re.search(pattern,string,flags=0) 全文搜索,不限定在哪里开始查找,找到第一个匹配对象立即返回,找不到返回none。只是找第一个。
Regex.search()可以指定位置。
5)re.fullmatch(pattern,string,flags=0)完全匹配。
regex.fullmatch(string) 整个字符串和正则表达式匹配。
import re
s = ”’bottle\nbag\nbig\napple”’
for i,c in enumerate(s,1):
print((i-1,c),end=’\n’ if i%8==0 else ‘ ‘)
print()

print(‘–match–‘)
result = re.match(‘b’,s)
print(1,result)
result= re.match(‘a’,s)
print(2,result)
result = re.match(‘^a’,s,re.M)
print(3,result)
result = re.match(‘^a’,s,re.S)
print(4,result)
regex = re.compile(‘a’)
result =regex.match(s)
print(5,result)
result=regex.match(s,15)
print(6,result)

print(‘–search–‘)
result = re.search(‘a’,s)
print(7,result)
regex = re.compile(‘b’)
result=regex.search(s,1)
print(8,result)
regex=re.compile(‘^b’,re.M)
result=regex.search(s)
print(8.5,result)
result=regex.search(s,8)
print(9,result)

print(‘–fullmatch–‘)
result=re.fullmatch(‘bag’,s)
print(10,result)
regex=re.compile(‘bag’)
result=regex.fullmatch(s)
print(11,result)
result = regex.fullmatch(s,7)
print(12,result)
result=regex.fullmatch(s,7)
print(13,result)
(0, ‘b’) (1, ‘o’) (2, ‘t’) (3, ‘t’) (4, ‘l’) (5, ‘e’) (6, ‘\n’) (7, ‘b’)
(8, ‘a’) (9, ‘g’) (10, ‘\n’) (11, ‘b’) (12, ‘i’) (13, ‘g’) (14, ‘\n’) (15, ‘a’)
(16, ‘p’) (17, ‘p’) (18, ‘l’) (19, ‘e’)
–match–
1 <_sre.SRE_Match object; span=(0, 1), match=’b’>
2 None
3 None
4 None
5 None
6 <_sre.SRE_Match object; span=(15, 16), match=’a’>
–search–
7 <_sre.SRE_Match object; span=(8, 9), match=’a’>
8 <_sre.SRE_Match object; span=(7, 8), match=’b’>
8.5 <_sre.SRE_Match object; span=(0, 1), match=’b’>
9 <_sre.SRE_Match object; span=(11, 12), match=’b’>
–fullmatch–
10 None
11 None
12 None
13 None

6)、全文搜索;
Re.findall(pattern,string,flags=0)全文搜索,全部搜索。 返回匹配项的列表
Regex.findall(string,)
Re.finditer() 返回匹配项的可迭代对象。返回的都是match对象
Regex.finditer()
import re
s = ”’bottle\nbag\nbig\napple”’
for i,c in enumerate(s,1):
print((i-1,c),end=’\n’ if i%8==0 else ‘ ‘)
print()

print(‘–findall–‘)
result = re.findall(‘b’,s)
print(1,result)
regex = re.compile(‘^b’)
result = regex.findall(s)
print(2,result)
regex=re.compile(‘^b’,re.M)
result=regex.findall(s,7)
print(3,result)
regex=re.compile(‘^b’,re.S)
result=regex.findall(s)
print(4,result)
regex=re.compile(‘^b’,re.M)
result=regex.findall(s,7,10)
print(5,result)
print(‘–finder–‘)
result=regex.finditer(s)
print(1,type(result))
print(2,next(result))
print(3,next(result))
(0, ‘b’) (1, ‘o’) (2, ‘t’) (3, ‘t’) (4, ‘l’) (5, ‘e’) (6, ‘\n’) (7, ‘b’)
(8, ‘a’) (9, ‘g’) (10, ‘\n’) (11, ‘b’) (12, ‘i’) (13, ‘g’) (14, ‘\n’) (15, ‘a’)
(16, ‘p’) (17, ‘p’) (18, ‘l’) (19, ‘e’)
–findall–
1 [‘b’, ‘b’, ‘b’]
2 [‘b’]
3 [‘b’, ‘b’]
4 [‘b’]
5 [‘b’]
–finder–
1 <class ‘callable_iterator’>
2 <_sre.SRE_Match object; span=(0, 1), match=’b’>
3 <_sre.SRE_Match object; span=(7, 8), match=’b’>

7、匹配替换:
re.sub(pattern,repleacement,string,count=0,flags=0) 替换
regex.sub(replacement,string,count=0) 替换
使用pattern对字符串string进行匹配,对匹配项使用replancement替换吧,可以是string,bytes,function。
re.subn(pattern,replacement,string,count=0,flags=0)输出二元组,提供替换的次数。
regex.subn()
regex = re.compile(‘b\wg’)
result = regex.sub(‘magedu’,s)
print(1,result)
result = regex.sub(‘magedu’,s,1)
print((2,result))

regex =re.compile(‘\s+’)
result = regex.subn(‘\t’,s)
print(3,result)
1 bottle
magedu
magedu
apple
(2, ‘bottle\nmagedu\nbig\napple’)
3 (‘bottle\tbag\tbig\tapple’, 3)

8、分隔字符串:
Re.split(pattern,string,maxsplit=0,flag=0)
Re.split分隔字符串
import re

s= ”’01 bottle
02 bag
03 big1
100 able”’

x = re.split(‘\s+\d+\s+’,’ ‘+s)
print(x)
[”, ‘bottle’, ‘bag’, ‘big1’, ‘able’]

9、分组:
使用小括号的pattern捕获的数据放到了组group中。
Match,search函数均可以返回match对象。Findall返回的是字符串列表。。Finditer一个个返回match对象。。
如果pattern中使用了分组,如果有匹配结果,会在match对象中。
1)使用group(N)方式返回对应的分组,1-N对应的是分组,0返回整个匹配的字符串。
2)如果使用了命名分组,可以使用group(‘name’)的方式取分组。
3)也可以使用groups()返回所有组。
4)使用groupdict返回所有命名的分组。
Matcher.group()
matcher.groups()返回的是二元组。
Matcher.groupdict()字典。
import re
s = ”’bottle\nbag\nbig\napple”’
for i,c in enumerate(s,1):
print((i-1,c),end=’\n’ if i%8==0 else ‘ ‘)
print()
regex = re.compile(‘(b\w+)’)
result = regex.match(s)
print(type(result))
print(1,’match’,result.groups())
result =regex.search(s,1)
print(2,’search’,result.groups())
regex = re.compile(‘(b\w+)\n(?P<name2>b\w+)\n(?P<name3>b\w+)’)
result = regex.match(s)
print(3,’match’,result)
print(4,result.group(3),result.group(2),result.group(1))
print(5,result.group(0).encode())
print(6,result.group(‘name2’),result.group(‘name3’))
print(6,result.groups())
print(7,result.groupdict())

result = regex.findall(s)
for x in result:
print(8,type(x),x)

regex = re.compile(‘(?P<head>b\w+)’)
result = regex.finditer(s)
for x in result:
print(9,type(x),x,x.group(),x.group(‘head’))
(0, ‘b’) (1, ‘o’) (2, ‘t’) (3, ‘t’) (4, ‘l’) (5, ‘e’) (6, ‘\n’) (7, ‘b’)
(8, ‘a’) (9, ‘g’) (10, ‘\n’) (11, ‘b’) (12, ‘i’) (13, ‘g’) (14, ‘\n’) (15, ‘a’)
(16, ‘p’) (17, ‘p’) (18, ‘l’) (19, ‘e’)
<class ‘_sre.SRE_Match’>
1 match (‘bottle’,)
2 search (‘bag’,)
3 match <_sre.SRE_Match object; span=(0, 14), match=’bottle\nbag\nbig’>
4 big bag bottle
5 b’bottle\nbag\nbig’
6 bag big
6 (‘bottle’, ‘bag’, ‘big’)
7 {‘name2’: ‘bag’, ‘name3’: ‘big’}
8 <class ‘tuple’> (‘bottle’, ‘bag’, ‘big’)
9 <class ‘_sre.SRE_Match’> <_sre.SRE_Match object; span=(0, 6), match=’bottle’> bottle bottle
9 <class ‘_sre.SRE_Match’> <_sre.SRE_Match object; span=(7, 10), match=’bag’> bag bag
9 <class ‘_sre.SRE_Match’> <_sre.SRE_Match object; span=(11, 14), match=’big’> big big
10、练习题:
1)判断邮箱地址。
\w+[-.\w]*@[\w-]+(\.[\w-]+)+
2)html提取:
<[^<>]+>(.*)<^<>+>
3)URL提取。
(\w+)://([^\s]+)
4)身份验证
身份证验证需要使用计算公式,最严格的应该是实名验证。
\d{17}[0-9xX]|\d{15}
5)单词统计利用makekey等进行查找。

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/97300

发表评论

登录后才能评论

This site uses Akismet to reduce spam. Learn how your comment data is processed.

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1823388528@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班