1.文件读写
(1)读文件
使用open()
传入文件和标识符:
f = open('D:/Workspace/PycharmProjects/test/beread.txt', 'r')//标识符'r'表示读
//如果文件不存在,就会抛出IOError错误,如果打开成功,就可以用read()方法一次把文件的全部内容读到内存
f.read()
//最后需要调用close()关闭文件
f.close()
如果文件读写过程中产生IOError
,后面的f.close()
就不会调用,文件就无法关闭,解决这个问题的第一种方法是使用try...finally
:
try:
f = open('/path/to/file', 'r')
print f.read()
finally:
if f:
f.close()
这么写比较繁琐,所以Python引入了with
语句来自动调用close
方法:
with open('/path/to/file', 'r') as f:
print f.read()
read()
方法会一次性读取文件的全部内容,文件比较小时,这种读取方法最方便;如果不能确定文件大小,反复调用read(size)
比较保险,size
表示每次最多读取size个字节的内容;如果是配置文件,调用readlines()
最方便:
for line in f.readlines():
print(line.strip()) //去掉末尾的'ln'
(2)file-like Object
像open()
函数返回的这种有个read()
方法的对象,在Python中统称为file-like Object。除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()
方法就行。
(3)读取二进制文件&非ASCII编码文件
前面讲的默认都是读取文本文件,并且是ASCII编码的文本文件。要读取二进制文件,比如图片,视频等等,要用标识符'rb'
打开:
open('D:/Workspace/PycharmProjects/test/beread.jpg', 'rb')
如果要读非ASCII编码的文件,就必须以二进制模式打开,再解码。比如GBK编码的文件:
f = open('D:/Workspace/PycharmProjects/test/gbk.txt', 'rb')
u = f.read().decode('gbk')
这样子手动装换太麻烦,Python提供了一个codecs模块来在读文件时自动转换编码,直接读出unicode:
import codecs
with codecs.open('D:/Workspace/PycharmProjects/test/gbk.txt', 'r', 'gbk') as f:
f.read()
(4)写文件
使用write()
函数,方法和读文件类似,只是标识符要改为'w'
或者'wb'
with open('/Users/michael/test.txt', 'w') as f:
f.write('Hello, world!')
2.操作文件和目录
Python内置的os
模块可以直接调用操作系统提供的接口函数。操作文件和睦的函数一部分放在os
模块中,一部分放在os.path
模块中:
os.path.abspath('.') //查看当前目录的绝对路径
D:\Workspace\PycharmProjects\test
#在该目录下创建一个新目录
#首先把新目录的完整路径表示出来
os.path.join('D:\Workspace\PycharmProjects\test', 'newcreate')
#然后创建一个新的目录:
os.mkdir('D:\Workspace\PycharmProjects\test\newcreate')
#删掉一个目录
os.rmdir('D:\Workspace\PycharmProjects\test\newcreate')
把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()
,这样可以正确处理不同操作系统的分隔符,拆分时也是同样道理,要用os.path.split()
,拆分后的后一部分总是最后级别的目录或文件名
os.path.split('D:\Workspace\PycharmProjects\test\newcreate')
('D:\Workspace\PycharmProjects\test','newcreate')
os.path.splitext()
可以直接得到文件扩展名
os.path.splitext('/path/to/file.txt')
('/path/to/file', '.txt')
对当前目录下文件的操作:
os.rename('beread.txt', 'newname.py')//文件重命名
os.remove('beread.jpg')//删除文件
但是os
模块中没有复制文件的函数,但在shutil
模块中提供了copyfile()
的函数,传入两个参数,第一个是被复制文件的名字,第二个是新文件的名字。
os.listdir('.') # 列出当前目录的所有文件和子目录
os.path.isdir(x) # 判断x是否为目录
os.path.isfile(x) # 判断x是否为文件
os.walk('.') # 遍历当前目录的所有文件和子目录和子目录的文件,返回值去pycharn里面看
文件操作的一些方法:https://www.cnblogs.com/tkinter/p/5631213.html
3.序列化
①Python提供cPickle
和pickle
两个模块来实现序列化,两个模块功能一样,只是前者是用c语言写的,速度快,所以导入的时候先尝试导入前者:
try:
import cPickle as pickle
except ImportError:
import pickle
d = dict(name = 'Bob', age = 20, score = 88)
pickle.dumps(d)
pickle.dumps()
方法把任意对象序列化成一个str,然后就可以把这个str写入文件,或者用另一个方法pickle.dump()
直接把对象序列化后写入一个file-like Object:
f = open('dump.txt', 'wb')
pickle.dum(d, f)
f.close()
#反序列化
f = open('dump.txt', 'rb')
d = pickle.load(f)
f.close()
print d
{'age': 20, 'score': 88, 'name': 'Bob'}
②JSON
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
Python的json
模块提供了转换方法:
import json
d = dict(name='Bob', age=20, score=88)
json.dumps(d) # dumps()方法返回一个内容为JSON标准的str
f = open('jsondump.txt', 'wb')
json.dump(d, f) # dump()方法把d转化为JSON后写入一个file-like Object.
f.close()
JSON同样有loads()
和load()
的方法来进行反序列化,loads()
把JSON类型的字符串反序列化,load()
从file-like Object读取字符串并且反序列化,需要注意的是反序列化得到的所有字符串对象默认都是unicode
而不是str
:
import json
f = open('dump.txt', 'rb')
d = json.load(f)
f.close()
print d
{u'age': 20, u'score': 88, u'name': u'Bob'}
③JSON进阶
class Student(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
s = Student('Bob', 20, 88)
print(json.dumps(s))
当直接用dumps(d)
序列化一个class
对象d时会报错,因为class
对象不是一个可序列化为JSON的对象,不过dumps()
方法还有很多可选参数,可选参数default
就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为类对象写一个转换函数,再把函数传入:
def change(std):
return {
'name': std.name
'age': std.age
'score': std.score
}
print(json.dumps(s, default = change))
另一种方法是通过class
实例的__dict__
属性,它就是一个dict
,用来存储实例变量。也有少数例外,比如定义了__slots__
的class
。
print(json.dumps(s, default=lambda obj: obj.__dict__))
反序列化的时候,同样要写一个函数传入loads()
的object_hook
,把dict
对象转化了类的实例:
def changeback(d):
return Student(d['name'], d['age'], d['score'])
json_str = '{"age": 20, "score": 88, "name": "Bob"}'
print(json.loads(json_str, object_hook = changeback))
4.正则表达式
①单子字符匹配
\d
匹配一个数字,\w
匹配一个字母或者数字,.
匹配任意字符,\s
匹配空格
②变长字符匹配
*
表示任意个字符,包括0,
+
表示至少一个字符,
?
表示0个或者一个字符,
用{n}
表示n个字符,
用{m,n}
表示m到n个字符
③'-'
这样的特殊字符要用'\'
转义
④进阶:
要做更精确的匹配,可以用[]
表示范围,比如:
[0-9a-zA-Z\_]
可以匹配一个数字、字母或者下划线;
[0-9a-zA-Z\_]+
可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'a100'
,'0_Z'
,'Py3000
‘等等;
[a-zA-Z\_][0-9a-zA-Z\_]*
可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串,也就是Python合法的变量;
[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}
更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)。
A|B
可以匹配A或B,所以(P|p)ython
可以匹配'Python'
或者'python'
。
^
表示行的开头,^\d
表示必须以数字开头。
$
表示行的结束,\d$
表示必须以数字结束。
⑤re模块
Python提供re
模块,包含所有正则表达式的功能,匹配使尽量使用r''
,这样就不需要转义:
import re
print re.match(r'\d{3}\s\-\s\d{3,8}', '010 - 12345')
<_sre.SRE_Match object at 0x0266EC28>
print re.match(r'\d{3}\-\d{3,8}', '010 - 12345')
None
如果match()
匹配成功,则返回一个Match
对象,否则返回None
⑥切分字符串
用re.split(s)
切分字符串比普通的`s.split(’ ‘)功能更强大,就算有连续的空格或者其他符号,都能切分出来:
re.split(r'[\s\,\;]+', 'a,b;; c d')
['a', 'b', 'c', 'd']
⑦分组
除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()
表示的就是要提取的分组,比如^(\d{3})-(\d{3,8}$)
就定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:
m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
print m.group(0) # group(0)永远是原始字符串
'010-12345'
print m.group(1), m.group(2) # group(1), group(2), ....表示第1、2、...个子串
'010' '12345'
print m.groups() # 打印出所有子串
('010', '12345')
⑧贪婪匹配
正则匹配默认是贪婪匹配,会尽可能多的匹配字符:
re.match(r'^(\d+)(0*)', '102300').groups()
('102300', '')
由于\d+
采用贪婪匹配,所以会把整个字符串全部匹配掉,所以后面的0*
只能匹配空字符串,要想\d+
采用非贪婪匹配,在其后面加个?
就可以:
re.match(r'^(\d+?)(0*)', '102300').groups()
('1023', '00')
⑨编译
当我们在Python中使用正则表达式时,re模块内部会干两件事情:
1.编译正则表达式,如果正则表达式的字符串本身不合法,会报错;
2.用编译后的正则表达式去匹配字符串。
如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配:
import re
re_pre = re.compile(r'^(\d{3})-(\d{3,8})$') #预编译
re_pre.match('010-12345').groups()
('010', '12345')