Python3学习笔记10-标准库之正则、时间、路径、文件管理、存储对象

原创
2016/06/10 12:46
阅读数 210

Python有一套很有用的标准库(standard library)。标准库会随着Python解释器,一起安装在你的电脑中的。它是Python的一个组成部分。这些标准库是Python为你准备好的利器,可以让编程事半功倍。

下面,我将根据我个人的使用经验中,挑选出标准库比较常用的**包(package)**介绍。 ##一、正则表达式 (re包) 我将从正则表达式开始讲Python的标准库。正则表达式是文字处理中常用的工具,而且不需要额外的系统知识或经验。我们会把系统相关的包放在后面讲解。

正则表达式(regular expression)主要功能是从字符串(string)中通过特定的模式(pattern),搜索想要找到的内容。

1、语法 之前,我们简介了字符串相关的处理函数。我们可以通过这些函数实现简单的搜索功能,比如说从字符串“I love you”中搜索是否有“you”这一子字符串。但有些时候,我们只是模糊地知道我们想要找什么,而不能具体说出我是在找“you”,比如说,我想找出字符串中包含的数字,这些数字可以是0到9中的任何一个。这些模糊的目标可以作为信息写入正则表达式,传递给Python,从而让Python知道我们想要找的是什么。

官方documentation

在Python中使用正则表达式需要标准库中的一个包re

import re
m = re.search('[0-9]','abcd4ef')
print(m.group(0))

re.search()接收两个参数,第一个'[0-9]'就是我们所说的正则表达式,它告诉Python的是:“听着,我从字符串想要找的是从0到9的一个数字字符”。

re.search()如果从第二个参数找到符合要求的子字符串,就返回一个对象m,你可以通过m.group()的方法查看搜索到的结果。如果没有找到符合要求的字符,re.search()会返回None

如果你熟悉Linux或者Perl, 你应该已经熟悉正则表达式。当我们打开Linux shell的时候,可以用正则表达式去查找或着删除我们想要的文件,比如说:

$rm book[0-9][0-9].txt

这就是要删除类似于book02.txt的文件。book[0-9][0-9].txt所包含的信息是,以book开头,后面跟两个数字字符,之后跟有".txt"的文件名。如果不符合条件的文件名,比如说:

bo12.txt
book1.txt
book99.text

都不会被选中。

Perl中内建有正则表达式的功能,据说是所有正则表达式系统中最强的,这也是Perl成为系统管理员利器的一个原因。

###2、正则表达式的函数

m = re.search(pattern, string)  # 搜索整个字符串,直到发现符合的子字符串。
m = re.match(pattern, string)   # 从头开始检查字符串是否符合正则表达式。必须从字符串的第一个字符开始就相符。

可以从这两个函数中选择一个进行搜索。上面的例子中,我们如果使用re.match()的话,则会得到None,因为字符串的起始为‘a’, 不符合'[0-9]'的要求。

对于返回的m, 我们使用**m.group()**来调用结果。(我们会在后面更详细解释m.group())

我们还可以在搜索之后将搜索到的子字符串进行替换:

str = re.sub(pattern, replacement, string) 

# 在string中利用正则变换pattern进行搜索,对于搜索到的字符串,用另一字符串replacement替换。返回替换后的字符串。

此外,常用的正则表达式函数还有:

re.split()    # 根据正则表达式分割字符串, 将分割后的所有子字符串放在一个表(list)中返回
re.findall()  # 根据正则表达式搜索字符串,将所有符合的子字符串放在一个表(list)中返回

(在熟悉了上面的函数后,可以看一下re.compile(),以便于提高搜索效率。)

###3、写一个正则表达式 关键在于将信息写成一个正则表达式。我们先看正则表达式的常用语法:

####(1)、单个字符:

.          任意的一个字符
a|b        字符a或字符b
[afg]      a或者f或者g的一个字符        
[0-4]      0-4范围内的一个字符
[a-f]      a-f范围内的一个字符
[^m]       不是m的一个字符
\s         一个空格
\S         一个非空格
\d         [0-9]
\D         [^0-9]
\w         [0-9a-zA-Z]
\W         [^0-9a-zA-Z]

####(2)、重复

紧跟在单个字符之后,表示多个这样类似的字符:

*         重复 >=0 次
+         重复 >=1 次
?         重复 0或者1 次
{m}       重复m次。比如说 a{4}相当于aaaa,再比如说[1-3]{2}相当于[1-3][1-3]
{m, n}    重复m到n次。比如说a{2, 5}表示a重复2到5次。小于m次的重复,或者大于n次的重复都不符合条件。

正则表达 相符的字符串举例 [0-9]{3,5} 9678 a?b b a+b aaaaab

####(3)、位置

^ 字符串的起始位置

$ 字符串的结尾位置

正则表达 相符的字符串举例 不相符字符串 ^ab.*c$ abeec cabeec (如果用re.search(), 将无法找到。)

####(4)、返回控制

我们有可能对搜索的结果进行进一步精简信息。比如下面一个正则表达式:

output_(\d{4})

该正则表达式用括号()包围了一个小的正则表达式,\d{4}。 这个小的正则表达式被用于从结果中筛选想要的信息(在这里是四位数字)。这样被括号圈起来的正则表达式的一部分,称为群(group)

我们可以m.group(number)的方法来查询群。group(0)整个正则表达的搜索结果group(1)是第一个群……

import re
m = re.search("output_(\d{4})", "output_1986.txt")
print(m.group(1))

输入图片说明

我们还可以将群命名,以便更好地使用m.group查询:

import re
m = re.search("output_(?P<year>\d{4})", "output_1986.txt")   #(?P<name>...) 为group命名
print(m.group("year"))

##二、时间与日期 (time, datetime包) Python具有良好的时间和日期管理功能。实际上,计算机只会维护一个挂钟时间(wall clock time),这个时间是从某个固定时间起点到现在的时间间隔。时间起点的选择与计算机相关,但一台计算机的话,这一时间起点是固定的。其它的日期信息都是从这一时间计算得到的。此外,计算机还可以测量CPU实际上运行的时间,也就是处理器时间(processor clock time),以测量计算机性能。当CPU处于闲置状态时,处理器时间会暂停。

###1、time包 time包基于C语言的库函数(library functions)。Python的解释器通常是用C编写的,Python的一些函数也会直接调用C语言的库函数

import time
print(time.time())   # wall clock time, unit: second
print(time.clock())  # processor clock time, unit: second

time.sleep()可以将程序置于休眠状态,直到某时间间隔之后再唤醒程序,让程序继续运行。

import time
print('start')
time.sleep(10)     # sleep for 10 seconds
print('wake up')

当我们需要定时地查看程序运行状态时,就可以利用该方法。

time包还定义了struct_time对象。该对象实际上是将挂钟时间转换为年、月、日、时、分、秒……等日期信息,存储在该对象的各个属性中(tm_year, tm_mon, tm_mday...)。下面方法可以将挂钟时间转换为struct_time对象:

st = time.gmtime()      # 返回struct_time格式的UTC时间
st = time.localtime()   # 返回struct_time格式的当地时间, 当地时区根据系统环境决定。
s  = time.mktime(st)    # 将struct_time格式转换成wall clock time

输入图片说明
所返回如下属性: hour, minute, second, microsecond year, month, day, weekday # weekday表示周几

###2、datetime包 ####(1)、简介

datetime包是基于time包的一个高级包, 为我们提供了多一层的便利。

datetime可以理解为date和time两个组成部分。date是指年月日构成的日期(相当于日历)time是指时分秒微秒构成的一天24小时中的具体时间(相当于手表)。你可以将这两个分开管理(datetime.date类,datetime.time类),也可以将两者合在一起(datetime.datetime类)。由于其构造大同小异,我们将只介绍datetime.datetime类。

比如说我现在看到的时间,是2012年9月3日21时30分,我们可以用如下方式表达:

import datetime
t = datetime.datetime(2012,9,3,21,30)
print(t)

输入图片说明

###(2)、运算

datetime包还定义了时间间隔对象(timedelta)。一个**时间点(datetime)**加上一个时间间隔(timedelta)可以得到一个新的时间点(datetime)。比如今天的上午3点加上5个小时得到今天的上午8点。同理,两个时间点相减会得到一个时间间隔。

import datetime
t      = datetime.datetime(2012,9,3,21,30)
t_next = datetime.datetime(2012,9,5,23,30)
delta1 = datetime.timedelta(seconds = 600)
delta2 = datetime.timedelta(weeks = 3)
print(t + delta1)
print(t + delta2)
print(t_next - t)

在给datetime.timedelta传递参数(如上的seconds和weeks)的时候,还可以是days, hours, milliseconds, microseconds。

两个datetime对象还可以进行比较。比如使用上面的t和t_next:

print(t > t_next)

###(3)、datetime对象与字符串转换

假如我们有一个的字符串,我们如何将它转换成为datetime对象呢?

一个方法是用上一讲的正则表达式来搜索字符串。但时间信息实际上有很明显的特征,我们可以用格式化读取的方式读取时间信息。

from datetime import datetime
format = "output-%Y-%m-%d-%H%M%S.txt" 
str    = "output-1997-12-23-030000.txt" 
t      = datetime.strptime(str, format)

我们通过format来告知Python我们的str字符串中包含的日期的格式。在format中,%Y表示年所出现的位置, %m表示月份所出现的位置……。

反过来,我们也可以调用datetime对象的**strftime()**方法,来将datetime对象转换为特定格式的字符串。比如上面所定义的t_next,

print(t_next.strftime(format))

具体的格式写法可参阅官方文档。 如果是Linux系统,也可查阅date命令的手册($man date),两者相通。

##三、路径与文件 (os.path包, glob包) ###1、os.path包 os.path包主要是处理路径字符串,比如说'/home/vamei/doc/file.txt',提取出有用信息。

import os.path
path = '/home/vamei/doc/file.txt'

print(os.path.basename(path))    # 查询路径中包含的文件名
print(os.path.dirname(path))     # 查询路径中包含的目录

info = os.path.split(path)       # 将路径分割成文件名和目录两个部分,放在一个表中返回
path2 = os.path.join('/', 'home', 'vamei', 'doc', 'file1.txt')  # 使用目录名和文件名构成一个路径字符串

p_list = [path, path2]
print(os.path.commonprefix(p_list))    # 查询多个路径的共同部分

此外,还有下面的方法: os.path.normpath(path) # 去除路径path中的冗余。比如'/home/vamei/../.'被转化为'/home' os.path还可以查询文件的相关信息(metadata)。文件的相关信息不存储在文件内部,而是由操作系统维护的,关于文件的一些信息(比如文件类型,大小,修改时间)。

import os.path 
path = '/home/vamei/doc/file.txt'

print(os.path.exists(path))    # 查询文件是否存在

print(os.path.getsize(path))   # 查询文件大小
print(os.path.getatime(path))  # 查询文件上一次读取的时间
print(os.path.getmtime(path))  # 查询文件上一次修改的时间

print(os.path.isfile(path))    # 路径是否指向常规文件
print(os.path.isdir(path))     # 路径是否指向目录文件

输入图片说明 (实际上,这一部份类似于Linux中的ls命令的某些功能)

###2、glob包 glob包最常用的方法只有一个, glob.glob()。该方法的功能与Linux中的ls相似,接受一个Linux式的文件名格式表达式(filename pattern expression),列出所有符合该表达式的文件(与正则表达式类似),将所有文件名放在一个表中返回。所以glob.glob()是一个查询目录下文件的好方法

该文件名表达式的语法与Python自身的正则表达式不同 (你可以同时看一下fnmatch包,它的功能是检测一个文件名是否符合Linux的文件名格式表达式)。 如下:

Filename Pattern Expression Python Regular Expression

  • .* ? . [0-9] same [a-e] same [^mnp] same 我们可以用该命令找出/home/vamei下的所有文件:
import glob
print(glob.glob('/home/vamei/*'))

##四、文件管理 (部分os包,shutil包) 在操作系统下,用户可以通过操作系统的命令来管理文件。Python标准库则允许我们从Python内部管理文件。相同的目的,我们有了两条途径。尽管在Python调用标准库的方式不如操作系统命令直接,但有它自己的优势。你可以利用Python语言,并发挥其他Python工具,形成组合的文件管理功能。Python or Shell? 这是留给用户的选择。本文中会尽量将两者相似的功能相对应。

###1、os包 os包包括各种各样的函数,以实现操作系统的许多功能。这个包非常庞杂。os包的一些命令就是用于文件管理。我们这里列出最常用的:

mkdir(path) 创建新目录,path为一个字符串,表示新目录的路径。相当于$mkdir命令

rmdir(path) 删除空的目录,path为一个字符串,表示想要删除的目录的路径。相当于$rmdir命令

listdir(path) 返回目录中所有文件。相当于$ls命令。

remove(path) 删除 path指向的文件。

rename(src, dst) 重命名文件,src和dst为两个路径,分别表示重命名之前和之后的路径。

chmod(path, mode) 改变path指向的文件的权限。相当于$chmod命令。

chown(path, uid, gid) 改变path所指向文件的拥有者和拥有组。相当于$chown命令。

stat(path) 查看path所指向文件的附加信息,相当于$ls -l命令。

symlink(src, dst) 为文件dst创建软链接,src为软链接文件的路径。相当于$ln -s命令。

getcwd() 查询当前工作路径 (cwd, current working directory),相当于$pwd命令。

比如说我们要新建目录new:

import os
os.mkdir('/home/vamei/new')

###2、shutil包

  • copy(src, dst) 复制文件,从src到dst。相当于$cp命令。

  • move(src, dst) 移动文件,从src到dst。相当于$mv命令。

比如我们想复制文件a.txt:

import shutil
shutil.copy('a.txt', 'b.txt')

想深入细节,请参照官方文档os, shutil。

结合本章以及之前的内容,我们把Python打造成一个文件管理的利器了。

##五、存储对象 (pickle包,cPickle包) 在之前对Python对象的介绍中,我提到过Python“一切皆对象”的哲学,在Python中,无论是变量还是函数,都是一个对象。当Python运行时,对象存储在内存中,随时等待系统的调用。然而,内存里的数据会随着计算机关机和消失,如何将对象保存到文件,并储存在硬盘上呢

计算机的内存中存储的是二进制的序列 (当然,在Linux眼中,是文本流)。我们可以直接将某个对象所对应位置的数据抓取下来,转换成文本流 (这个过程叫做serialize),然后将文本流存入到文件中。由于Python在创建对象时,要参考对象的类定义,所以当我们从文本中读取对象时,必须在手边要有该对象的类定义,才能懂得如何去重建这一对象。从文件读取时,对于Python的内建(built-in)对象 (比如说整数、词典、表等等),由于其类定义已经载入内存,所以不需要我们再在程序中定义类。但对于用户自行定义的对象,就必须要先定义类,然后才能从文件中载入对象 (比如面向对象的基本概念中的对象那个summer)

###1、pickle包 对于上述过程,最常用的工具是Python中的pickle包

####(1)、将内存中的对象转换成为文本流:

import pickle

# define class
class Bird(object):
    have_feather = True
    way_of_reproduction  = 'egg'

summer       = Bird()                 # construct an object
picklestring = pickle.dumps(summer)   # serialize object

使用pickle.dumps()方法可以将对象summer转换成了字符串 picklestring(也就是文本流)。随后我们可以用普通文本的存储方法来将该字符串储存在文件(文本文件的输入输出)。

将文本流写入文件:

输入图片说明

new.txt文件: 注:hello, python! 为文件原来的字符,后边为追加的文本留。

输入图片说明

当然,我们也可以使用**pickle.dump()**的方法,将上面两部合二为一:

import pickle

# define class
class Bird(object):
    have_feather = True
    way_of_reproduction  = 'egg'

summer       = Bird()                        # construct an object
fn           = 'a.pkl'
with open(fn, 'w') as f:                     # open file with write-mode
    picklestring = pickle.dump(summer, f)   # serialize and save object

对象summer存储在文件a.pkl

###(2)、重建对象

首先,我们要从文本中读出文本,存储到字符串 (文本文件的输入输出)。然后使用**pickle.loads(str)**的方法,将字符串转换成为对象。要记得,此时我们的程序中必须已经有了该对象的类定义。

此外,我们也可以使用pickle.load()的方法,将上面步骤合并:

import pickle

# define the class before unpickle
class Bird(object):
    have_feather = True
    way_of_reproduction  = 'egg'

fn     = 'a.pkl'
with open(fn, 'r') as f:
    summer = pickle.load(f)   # read file and build object

###2、cPickle包 cPickle包的功能和用法与pickle包几乎完全相同 (其存在差别的地方实际上很少用到),不同在于cPickle是基于c语言编写的,速度是pickle包的1000倍。对于上面的例子,如果想使用cPickle包,我们都可以将import语句改为:

import cPickle as pickle

就不需要再做任何改动了。

注:本Python学习笔记是按照Vamei的博客教程来学习的,如有兴趣可以参考Vamei Python快速开发博文

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
6 收藏
0
分享
返回顶部
顶部