python 常用模块
re 模块
正则表达式
需求
在线测试工具 : http://tool.chinaz.com/regex/
正则表达式,只和字符串相关,在测试工具中,你输入的每一个字都是字符串. 如果在一个位置上的一个值,不会出现什么变化,是不需要规则的.
如果用"1"去匹配"1",或者"2"匹配"2",直接就可以匹配上,在python中字符串都能够轻松做到.
正则表达式更多的是考虑在同一个位置上,可以出现的字符的范围.
1.字符组: [字符组]
在同一个位置上可能出现的各种字符组成一个字符组,在正则表达式中用 [ ] 表示.
字符分为很多,比如,数字/字母/标点等
假如你现在要求一个位置,"只能出现一个数字",name这个位置上的字符只能是 0 1 2 3 4 5 6 7 8 9 其中的一个.
字符组: [] 匹配一个位置上的字符
写在中括号中的内容都出现在下面某一个字符的位置上
都是符合规则的, 且[]中的内容要有序
要匹配什么就添加什么
[0-9] 0123456789
[a-z] abcdefghijklmnopqrstuvwxyz
[A-Z] ABCDEF....
[Z-a] 是可以的,因为在ASCII中,大写字母在小写字母之前
[a-zA-Z] 匹配大小写,不能是[A-z]因为90-97之间有其他的字符
[a-zA-Z0-9_] 等价于 \w : 匹配数字字母下划线
ACSII中: Z 90 a 97
A-Z: 65 - 90
a-z: 97 - 122
有一些有特殊意义的元字符进入字符组中,回恢复本来的意义,是什么匹配什么.
如 [ . | [ ( ] 得到 . | [ (
- 减号在中括号中表示到,如1-9,1到9,在中括号中想输出减号,需要转义, "\-"
正则
|
待匹配字符
|
匹配 |
说明
|
[0123456789]
|
8
|
True
|
在一个字符组里枚举合法的所有字符,字符组里的任意一个字符 |
[0123456789]
|
a
|
False
|
由于字符组中没有"a"字符,所以不能匹配
|
[0-9]
|
7
|
True
|
也可以用-表示范围,[0-9]就和[0123456789]是一个意思
|
[a-z]
|
s
|
True
|
同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示
|
[A-Z]
|
B
|
True
|
[A-Z]就表示所有的大写字母
|
[0-9a-fA-F]
|
e
|
True
|
可以匹配数字,大小写形式的a~f,用来验证十六进制字符
|
2. 元字符
元字符:
\w : [a-zA-Z0-9] 匹配数字字母下划线 word,转义w.
\\w: 表示\w, 第一个\将第二个\转义后,不再具有转义的功能,因此结果为\w
\\\w: 不符合规则
\\\\w: 表示第一个\转义第二个\得到"\".同理第三个\转义第四个\得到"\".
w仍然为w,因此最终结果是"\\w".
\d: [0-9] 匹配左右的数字 digit
\s: 匹配左右的空白符(3个),(空格,回车换行符,tab制表符)
\t: 匹配tab制表符
\n: 匹配回车(换行符)
: 空格
\W: 匹配非数字字母下划线
\D: 匹配非数字
\S: 匹配非空白符
[\s\S], [\d\D], [\w\W]: 三组全集,匹配所有的字符. 意义不大
\b: 表示匹配单词的边界 比如: ing\b ,表示匹配结尾的ing. blingbling
\bl, 表示开头是l的单词.
总结:\w, \d, \s(\n \t), \b, \W, \D, \S
^: 匹配一个字符串的开始,以什么什么开始
尖角号,每个字符串都有一个默认的开始符和结尾符.
^hello "hello hello hello" 得到的是第一个hello,与开始符挨着的.
$: 匹配一个字符串的结束,以什么什么结尾
hello$
^ 和 $: ^hello$ 表示他们之间的字符串要和匹配的字符串完全一样,才能匹配出来
^\d\d\d\d\d\d\d\d\d\d\d$, 表示匹配的是11位数字,如手机号.
开始符和结束符,限定了里面的内容.
^和$ 只能出现在开头和结尾
. : 点, 表示出了换行符之外的所有字符.但只能表示一个字符
[^]: 非字符组,只要不出现在中括号中的内容都可以匹配.^尖角号写在最前面.
如: [^a],匹配非a的字符,
|: 或, A|B,符合A规则或B规则的都可以匹配
如果A规则是B规则的一部分,且A规则要比B规则要苛刻,更长
(): 分组, 表示给几个字符加上量词约束的需求的时候,就给这几个字符加上量词
元字符
|
匹配内容
|
| . | 匹配除换行符以外的任意字符 |
| \w | 匹配字母或数字或下划线 |
| \s | 匹配任意的空白符 |
| \d | 匹配数字 |
| \n | 匹配一个换行符 |
| \t | 匹配一个制表符 |
| \b | 匹配一个单词的结尾 |
| ^ | 匹配字符串的开始 |
| $ | 匹配字符串的结尾 |
| \W |
匹配非字母或数字或下划线
|
| \D |
匹配非数字
|
| \S |
匹配非空白符
|
| a|b |
匹配字符a或字符b
|
| () |
匹配括号内的表达式,也表示一个组
|
| [...] |
匹配字符组中的字符
|
| [^...] |
匹配除了字符组中字符的所有字符
|
3. 量词
量词:
{}: {n}表示前面紧挨着一个字符出现n次.
1[3-9]\d{9}手机号, {9}表示前面紧挨着的\d出现9次.
{n,}表示前面紧挨着一个字符出现至少n次.
{n,m}表示前面紧挨着一个字符出现n到m次.
? : 表示匹配量词之前的字符出现 0次 或者 1次. 表示可有可无
+ : 表示匹配量词之前的字符出现 1次 或者 多次
* : 表示匹配量词之前的字符出现 0次 或者 多次
量词
|
用法说明
|
| * | 重复零次或更多次 |
| + | 重复一次或更多次 |
| ? | 重复零次或一次 |
| {n} | 重复n次 |
| {n,} | 重复n次或更多次 |
| {n,m} | 重复n到m次 |
. ^ $
| 正则 | 待匹配字符 | 匹配 结果 |
说明 |
| 海. | 海燕海娇海东 | 海燕海娇海东 | 匹配所有"海."的字符 |
| ^海. | 海燕海娇海东 | 海燕 | 只从开头匹配"海." |
| 海.$ | 海燕海娇海东 | 海东 | 只匹配结尾的"海.$" |
* + ? { }
| 正则 | 待匹配字符 | 匹配 结果 |
说明 |
| 李.? | 李杰和李莲英和李二棍子 |
李杰 |
?表示重复零次或一次,即只匹配"李"后面一个任意字符
|
| 李.* | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 |
*表示重复零次或多次,即匹配"李"后面0或多个任意字符
|
| 李.+ | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 |
+表示重复一次或多次,即只匹配"李"后面1个或多个任意字符
|
| 李.{1,2} | 李杰和李莲英和李二棍子 |
李杰和 |
{1,2}匹配1到2次任意字符
|
注意:前面的 *,+,? 等都是贪婪匹配,也就是尽可能匹配,量词后面加再 ? 号使其变成惰性匹配
| 正则 | 待匹配字符 | 匹配 结果 |
说明 |
| 李.*? | 李杰和李莲英和李二棍子 | 李 李 李 |
惰性匹配 |
字符集[ ][^ ]
| 正则 | 待匹配字符 | 匹配 结果 |
说明 |
| 李[杰莲英二棍子]* | 李杰和李莲英和李二棍子 |
李杰 |
表示匹配"李"字后面[杰莲英二棍子]的字符任意次
|
| 李[^和]* | 李杰和李莲英和李二棍子 |
李杰 |
表示匹配一个不是"和"的字符任意次
|
| [\d] | 456bdha3 |
4 |
表示匹配任意一个数字,匹配到4个结果
|
| [\d]+ | 456bdha3 |
456 |
表示匹配任意个数字,匹配到2个结果
|
分组 () 与 或 |[^ ]
身份证号码为15位或18位,其中: 首位不能是0, 15位的全部为数字.
18位的最后一位可能是数字,可能是X.
| 正则 | 待匹配字符 | 匹配 结果 |
说明 |
| ^[1-9]\d{13,16}[0-9x]$ | 110101198001017032 |
110101198001017032 |
表示可以匹配一个正确的身份证号 |
| ^[1-9]\d{13,16}[0-9x]$ | 1101011980010170 |
1101011980010170 |
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字
|
| ^[1-9]\d{14}(\d{2}[0-9x])?$ | 1101011980010170 |
False |
现在不会匹配错误的身份证号了 |
| ^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ | 110105199812067023 |
110105199812067023 |
表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14}
|
转义符 \
在正则中有特殊意义的字符想让它变为没有意义的,要在字符的前面加上"\".
在正则中一些没有特殊意义的字符,加上"\"可能会变成有意义的字符.
在正则表达式中,有很多有特殊意义的是元字符,比如\d和\s等,如果要在正则中匹配正常的"\d"而不是"数字"就需要对"\"进行转义,变成'\\'。
在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。所以如果匹配一次"\d",字符串中要写成'\\d',那么正则里就要写成"\\\\d",这样就太麻烦了。这个时候我们就用到了 r'\d' 这个概念,此时的正则是 r'\\d' 就可以了。
| 正则 | 待匹配字符 | 匹配 结果 |
说明 |
| \d | \d | False |
因为在正则表达式中\是有特殊意义的字符,所以要匹配\d本身,用表达式\d无法匹配
|
| \\d | \d | True |
转义\之后变成\\,即可匹配
|
| "\\\\d" | '\\d' | True |
如果在python中,字符串中的'\'也需要转义,所以每一个字符串'\'又需要转义一次
|
| r'\\d' | r'\d' | True |
在字符串之前加r,让整个字符串不转义,原样输出
|
贪婪匹配
贪婪匹配, 会在允许的量词范围内,取最长的结果
\d+8 : 匹配左右符合的数字字符,以最后一个8结束.
转为非贪婪模式: 在量词的后面添加一个问号,表示非贪婪模式.
.*?x : 匹配任意非换行符字符任意长度,直到遇到 x 位置.
比如: \d+?8 : 表示匹配任意数字,以8结尾.
(1) 几种常用的非贪婪匹配:
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
(2) . * ? 的用法
. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x
就是取前面任意长度的字符,直到一个x出现
. ? ? X 遇到x停止

re模块下的常用方法
♥♥♥ re模块需要引入: import re # 不要将py文件的名字和已知模块的名字重名
re模块中的基本方法
1) 查找方法
.findall()♥ 返回列表,找所有的匹配项
.search()♥ 匹配就返回一个变量,通过group()取匹配的第一个值, 不匹配就返回None,group()会报错
.match() 相当于search的正则表达式中加了一个'^'
2) 字符串处理的扩展: 切割和替换
.split() 切割, 返回列表,按照正则规则切割,默认匹配到的内容会被切掉.
若正则表达式加了括号,为分组后,默认切掉的内容也会保存下来,存储在列表中.
.sub() / subn() 替换, 按照正则规则去寻找要被替换掉的内容,subn()返回元组,(替换内容,替换次数)
3) re模块的进阶
.compile()♥ 编译一个正则表达式,用这个结果去 .search .match .findall .finditer 能够节省时间
.finditer()♥ 返回迭代器, 所有结果都在这个迭代器中,需要通过循环+group()的形式取值,节省空间
查找:
#=================================
# findall : 匹配所有 每一项都是列表中的一个元素
ret = re.findall('\d+','sjkhk172按实际花费928') # 正则表达式,带匹配的字符串,flag
print(ret)
ret = re.findall('\d','sjkhk172按实际花费928') # 正则表达式,带匹配的字符串,flag
print(ret)
# ['172', '928']
# ['1', '7', '2', '9', '2', '8']
#=================================
# search : 只匹配从左到右的第一个,得到的不是直接的结果,而是一个变量,
# 通过这个变量的group方法来获取结果,如果没有匹配到,会返回None,使用group会报错
ret = re.search('\d+','sjkhk172按实际花费928')
print(ret) # 内存地址,这是一个正则匹配的结果
print(ret.group()) # 通过ret.group()获取真正的结果
# [172]
# search匹配不存在时,会报错
ret = re.search('\d','owghabDJLBNdgv')
print(ret.group()) # 匹配不存在 会报错,因此,要如下进行判断
ret = re.search('\d+','owghabDJLBNdgv')
if ret : # 内存地址,这是一个正则匹配的结果 进行if判断 再输出便不会报错
print(ret.group()) # 通过ret.group()获取真正的结果 此题为空
#==================================
# match 从头开始匹配,相当于search中的正则表达式加上一个 ^
ret = re.match('\d+','172sjkhk按实际花费928')
print(ret)
print(ret.group())
# <_sre.SRE_Match object; span=(0, 3), match='172'>
# 172
# 字符串处理的扩展 : 替换 切割
#===============================
# split
s = 'alex|taibai|egon|'
print(s.split('|'))
s = 'alex83taibai40egon25'
ret = re.split('\d+',s)
print(ret)
# ['alex', 'taibai', 'egon', ''] #末尾字符进行切割时,末尾会有一个空的字符
# ['alex', 'taibai', 'egon', '']
#===============================
# sub # 旧的 新的 字符串 替换次数
ret = re.sub('\d+','H','alex83taibai40egon25') #默认全部替换
print(ret)
ret = re.sub('\d+','H','alex83taibai40egon25',1) #替换1次
print(ret)
# subn 返回一个元组,第二个元素是替换的次数
ret = re.subn('\d+','H','alex83taibai40egon25') #返回替换次数,元组形式
print(ret)
# alexHtaibaiHegonH
# alexHtaibai40egon25
# ('alexHtaibaiHegonH', 3)
# re模块的进阶 : 时间/空间
#==================================
# compile 节省你使用正则表达式解决问题的时间
# 编译 正则表达式 编译成 字节码
# 在多次使用的过程中 不会多次编译
ret = re.compile('\d+') # 已经完成编译了
print(ret) # re.compile('\\d+') 编译后为 \\d+
res = ret.findall('alex83taibai40egon25')
print(res) #['83', '40', '25']
res = ret.search('sjkhk172按实际花费928')
print(res.group()) #172
#====================================
# finditer 节省你使用正则表达式解决问题的空间/内存
ret = re.finditer('\d+','alex83taibai40egon25') # 获取的ret为迭代器
for i in ret:
print(i.group())
# 83
# 40
# 25
在Python中使用正则表达式的特点和问题 : 分组在re模块中的使用 分组优先
分组的特点:
优先显示,当匹配的内容和不想匹配的内容混在一起的时候,就匹配出所有内容,但是对实际需要的内容进行分组,优先获取.
1) 分组 在 search() 中
可以通过 .group( n), 直接获取到正则表达式 匹配后的字符串中 的第n个分组中的内容.
n为空时,默认获取的是匹配后的字符串所有内容
s = '<a>wahaha</a>' # 标签语言 html 网页
ret = re.search('<(\w+)>(\w+)</(\w+)>',s)
print(ret.group()) # 所有的结果 <a>wahaha</a>
print(ret.group(1)) # a 数字参数代表的是取对应分组中的内容,顺序索引从1开始
print(ret.group(2)) # wahaha
print(ret.group(3)) # a
2) 分组 在 findall() 中
优先获取分组内的内容, 当正则表达式中本身就含有分组括号时, 必要时要取消分组 ( ?: 正则表达式)
# 为了findall也可以顺利取到分组中的内容,有一个特殊的语法,就是优先显示分组中的内容.
s = '<a>wahaha</a>' # 标签语言 html 网页
ret = re.findall('(\w+)',s) #\w+ 匹配的是['a','wahaha','a'] 加上分组后都能取出来
print(ret)
ret = re.findall('>(\w+)<',s)# >\w+< 匹配的是 ['>wahaha<'] 加上分组后只去分组内的内容即['wahaha']
print(ret)
# ['a', 'wahaha', 'a']
# ['wahaha']
# 取消find中的分组优先 (?:正则表达式)
ret = re.findall('\d+(\.\d+)?','1.234*4') #按照优先分级会只取小数后的内容是不对的
print(ret) #['.234', ''] 并非是想要的小数和整数,因此此时需要取消分组
ret = re.findall('\d+(?:\.\d+)?','1.234*4')
print(ret) #['1.234', '4']
3) 分组在 split() 中
# split中正则表达式加分组后即 (正则表达式) 表示被切割掉的内容也会保存下来
ret = re.split('\d+','alex83taibai40egon25')
print(ret)
ret = re.split('(\d+)','alex83taibai40egon25aa')
print(ret) #正则加整体加分组表示被切割内容保存下来
# ['alex', 'taibai', 'egon', '']
# ['alex', '83', 'taibai', '40', 'egon', '25', 'aa']
4) 分组命名: (?P<组名>正则表达式) 使用: (?P<name>)
多用于search()中, 通过group(名称) 直接查找内容
正则表达式中匹配有相似内容时如下情况:
# 2018-12-06 # 2018.12.6 # 2018 12 06 # 12:30:30
# 分组命名 (?P<这个组的名字>正则表达式)
s = '<a>wahaha</a>'
ret = re.search('>(?P<con>\w+)<',s) #该分组命名为: con
print(ret.group(1)) #wahaha
print(ret.group('con')) #wahaha
# 分组命名用途:
# 判断标签中<>中内容是否一致
#方法一: 利用group
s = '<a>wahaha</a>'
pattern = '<(\w+)>(\w+)</(\w+)>'
ret = re.search(pattern,s)
print(ret.group(1) == ret.group(3)) #True
# 方法二: 利用分组命名
# 使用前面的分组 要求使用这个名字的分组和前面同名分组中的内容匹配的必须一致
pattern = '<(?P<tab>\w+)>(\w+)</(?P=tab)>'
ret = re.search(pattern,s)
print(ret) #<_sre.SRE_Match object; span=(0, 13), match='<a>wahaha</a>'>
正则表达式的使用技巧
例如: 获取某些字符串中的整数 (不包含小数)
错误演示 :
# 从"1-2*(60+(-40.35/5)-(-4*3))"中取整数
ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
# ['1', '2', '60', '40', '35', '5', '4', '3'] #40.35拆成了40 和 35 不对
正确推导 : 需要过滤掉小数
ret=re.findall(r"\d+\.\d+|\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret) #整数和小数同时取出
# ['1', '2', '60', '40.35', '5', '4', '3']
ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
ret.remove('') # 整数部分加上分组 优先获取 得到整数部分
print(ret)
# ['1', '2', '60', '5', '4', '3']
random 模块
使用时需要引入模块: import random
1) 取随机小数
.random() 取0-1之间的小数
.uniform(1,3) 取1-3之间的小数
print(random.random()) # 取0-1之间的小数 (0,1)
print(random.uniform(1,2)) # 取1-2之间的小数 (1,2)
2) 取随机整数
.randint() 顾头顾尾
.ranrange() 顾头不顾尾
print(random.randint(1,2)) # [1,2] 包括2
print(random.randrange(1,2)) # [1,2) 不包括2
print(random.randrange(1,200,2)) # [1,200) 取奇数
3) 从列表中随机抽取值 : 抽奖 彩票 列表可换成元组
.choice(列表名) 从列表中取1个
.sample(列表名 , n) 从列表中取n个
ls = ['a','b',(1,2),123]
print(random.choice(ls))
print(random.sample(ls,2))
4) 打乱列表的顺序 : 洗牌
.shuffle(列表名)
ls = ['a','b',(1,2),123]
random.shuffle(ls) # 不需要赋值 没有返回值 直接在原列表中进行修改
print(ls)
练习: 生成随机验证码 纯数字 或 数字字母均可
import random
def code(n = 6,alpha = True):
s = ''
for i in range(n):
num = str(random.randint(0,9))
if alpha:
alpha_upper = chr(random.randint(65,90))
alpha_lower = chr(random.randint(97,122))
num = random.choice([num,alpha_upper,alpha_lower])
s += num
return s
print(code(4,False))
print(code(alpha=False))
time 模块
使用时需要导入模块: import time
# 常用方法
time.sleep(2) # 以秒为单位, 指程序在此处会延迟2秒 print('世界,你好!')
time.time() #获取的是当前时间戳时间(浮点型的)
表示时间的三种方式:
1) 时间戳时间(timestamp) : 通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
2) 结构化时间 (元组形式)struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等)
| 索引(Index) | 属性(Attribute) | 值(Values) |
|---|---|---|
| 0 | tm_year(年) | 比如2011 |
| 1 | tm_mon(月) | 1 - 12 |
| 2 | tm_mday(日) | 1 - 31 |
| 3 | tm_hour(时) | 0 - 23 |
| 4 | tm_min(分) | 0 - 59 |
| 5 | tm_sec(秒) | 0 - 60 |
| 6 | tm_wday(weekday) | 0 - 6(0表示周一) |
| 7 | tm_yday(一年中的第几天) | 1 - 366 |
| 8 | tm_isdst(是否是夏令时) | 默认为0 |
结构化时间只能取值, 不能修改
3) 格式化时间 字符串(Format String): ‘1999-12-06’ '2018.08.20'等形式
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身
python中时间日期格式化符号:
三种时间格式的形式:
#当前时间戳 (浮点型)
print(time.time())
# 1534753759.6306567
# 当前结构化时间 (元组)
print(time.localtime())
#time.struct_time(tm_year=2018, tm_mon=8, tm_mday=20,
#tm_hour=16, tm_min=30, tm_sec=8, tm_wday=0, tm_yday=232, tm_isdst=0)
# 当前格式化时间 (字符串类型)
print(time.strftime('%Y-%m-%d %H:%M:%S'))
# 2018-08-20 16:33:02
几种格式之间的转化 :

#时间戳-->结构化时间 #time.gmtime(时间戳) #UTC时间,与英国伦敦当地时间一致 #time.localtime(时间戳) #当地时间。例如我们现在在北京执行这个方法:与UTC时间相差8小时,UTC时间+8小时 = 北京时间 >>>time.gmtime(1500000000) time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=2, tm_min=40, tm_sec=0, tm_wday=4,
tm_yday=195, tm_isdst=0) >>>time.localtime(1500000000) time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, tm_sec=0, tm_wday=4,
tm_yday=195, tm_isdst=0) #结构化时间-->时间戳 #time.mktime(结构化时间) >>>time_tuple = time.localtime(1500000000) >>>time.mktime(time_tuple) 1500000000.0
#结构化时间-->字符串时间 #time.strftime("格式定义","结构化时间") 结构化时间参数若不传,则显示当前时间 >>>time.strftime("%Y-%m-%d %X") '2017-07-24 14:55:36' >>>time.strftime("%Y-%m-%d",time.localtime(1500000000)) '2017-07-14' #字符串时间-->结构化时间 #time.strptime(时间字符串,字符串对应格式) >>>time.strptime("2017-03-16","%Y-%m-%d") time.struct_time(tm_year=2017, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0,
tm_wday=3,tm_yday=75,tm_isdst=-1) >>>time.strptime("07/24/2017","%m/%d/%Y") time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24, tm_hour=0, tm_min=0, tm_sec=0,
tm_wday=0, tm_yday=205, tm_isdst=-1)

#结构化时间 --> %a %b %d %H:%M:%S %Y串
#time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串
>>>time.asctime(time.localtime(1500000000))
'Fri Jul 14 10:40:00 2017'
>>>time.asctime()
'Mon Jul 24 15:18:33 2017'
#时间戳 --> %a %b %d %H:%M:%S %Y串
#time.ctime(时间戳) 如果不传参数,直接返回当前时间的格式化串
>>>time.ctime()
'Mon Jul 24 15:19:07 2017'
>>>time.ctime(1500000000)
'Fri Jul 14 10:40:00 2017'
练习: 题4 计算时间差
# 1.查看一下2000000000时间戳时间表示的年月日
# 时间戳 - 结构化 - 格式化
struct_t = time.localtime(2000000000)
print(struct_t)
print(time.strftime('%y-%m-%d',struct_t))
# 2.将2008-8-8转换成时间戳时间
t = time.strptime('2008-8-8','%Y-%m-%d')
print(time.mktime(t))
# 3.请将当前时间的当前月1号的时间戳时间取出来 - 函数
# 2018-8-1
def get_time():
st = time.localtime()
st2 = time.strptime('%s-%s-1'%(st.tm_year,st.tm_mon),'%Y-%m-%d')
return time.mktime(st2)
print(get_time())
# 4.计算时间差 - 函数版本
# 2018-8-19 22:10:8 2018-8-20 11:07:3
# 经过了多少时分秒
def js_time(n,m):
struct_time1 = time.strptime(n,'%Y-%m-%d %H:%M:%S')
struct_time2 = time.strptime(m,'%Y-%m-%d %H:%M:%S')
sta_time1 = time.mktime(struct_time1)
sta_time2 = time.mktime(struct_time2)
cha_statime = sta_time2 - sta_time1
stime = time.gmtime(cha_statime) #时间差转化为伦敦结构化时间 需要减去1970-1-1 0点
time_c = '%s年%s月%s日%s时%s分%s秒'%(stime.tm_year-1970,stime.tm_mon-1,stime.tm_mday-1,
stime.tm_hour,stime.tm_min,stime.tm_sec)
return time_c
s = js_time('2018-8-19 22:10:8','2018-8-20 11:07:3')
print(s)
sys 模块
需要导入 : import sys sys 模块是与python解释器交互的一个接口
sys.argv 命令行参数list,第一个元素是程序本身的路径
sys.exit (n) 退出程序,正常退出时exiit(0), 错误退出时sys.exit(1)
sys.version 获取Python解释器的版本信息
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值, (显示模块的存储路径)
sys.platform 返回操作系统瓶体的名称
sys.modules 导入到内存中的所有模块的名字: 这个模块的内存地址
1) sys.argv
当你在命令行执行python文件,而不是在pycharm中执行这个文件的时候,一般情况下:
你的命令>>>python py文件路径 参数1 参数2 参数3 ......
sys.argv = ['py文件路径','参数1','参数2','参数3'......]
好处: 这些需要输入的参数不需要再程序中以input的形式输入了
文件名: 文件路径不能有中文和空格, 所有的文件名都应该符合变量命名的规范.
# argv的第一个参数,是python这个命值令后面的路径,在终端中可以继续添加元素
print(sys.argv)
#['E:/A学习/python--study/untitled/code/5.sys模块.py']
# 在cmd终端运行 在路径py文件后 直接输入用户名和密码即可
usr = sys.argv[1]
pwd = sys.argv[2]
if usr == 'alex' and pwd == 'alex3714':
print('登录成功')
else:
exit()

2) sys.path
模块搜索路径,是一个列表,这个列表中存的都是文件夹的绝对路径
模块是存储在硬盘上的,使用时 import ===>> 这个模块才会到内存中
一个模块能否被顺利导入, 因为这个模块所在的文件件在sys.path的列表中
内置模块和第三方模块安装之后,不需要操作sys.path,直接用就可以
如果一个模块导入不进来,那把这个模块的文件夹添加到sys.path中就行了
自定义模块的时候,导入模块的时候,还需要再关注 sys.path
import sys
print(sys.path) # 返回模块的路径等
# ['E:\\A学习\\python--study\\untitled\\code', 'E:\\A学习\\python--study\\untitled',
# 'D:\\Program Files (x86)\\Python36\\python36.zip',
# 'D:\\Program Files (x86)\\Python36\\DLLs', 'D:\\Program Files (x86)\\Python36\\lib',
# 'D:\\Program Files (x86)\\Python36', 'D:\\Program Files (x86)\\Python36\\lib\\site-packages',
# 'D:\\Program Files (x86)\\PyCharm 2018.1.3\\helpers\\pycharm_matplotlib_backend']
3) sys.modules
已经导入到内存中的所有模块的名字 : 这个模块的内存地址
所有被导入的模块的内存地址都存在sys.modules里
import re
import sys
print(sys.modules) # 是我们导入到内存中的所有模块的名字 : 这个模块的内存地址
print(sys.modules['re'].findall('\d','abc126')) # 找到导入的re模块 同样可以使用findall()函数
print(re.findall('\d','abc126'))
# ['1', '2', '6']
# ['1', '2', '6']
os 模块
需要导入 : import os os 模块是和操作系统交互的模块
方法小总结
os.makedirs('dirname1/dirname2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
os.stat('path/filename') 获取文件/目录信息
os.system("bash command") 运行shell命令,直接显示
os.popen("bash command).read() 运行shell命令,获取执行结果
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.path
os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
注意: os.stat('path/filename') 获取文件/目录信息 的结构说明
stat 结构:
st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。
st_uid: 所有者的用户ID。
st_gid: 所有者的组ID。
st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。
st_atime: 上次访问的时间。
st_mtime: 最后一次修改的时间。
st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。
stat 结构
os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
# 递归方法
def func(path): # r'D:\sylar\s15'
size_sum = 0
name_lst = os.listdir(path)
for name in name_lst:
path_abs = os.path.join(path,name)
if os.path.isdir(path_abs):
size = func(path_abs)
size_sum += size
else:
size_sum += os.path.getsize(path_abs)
return size_sum
ret = func(r'D:\sylar\s15')
print(ret)
# 循环 # 堆栈思想
# 列表 满足一个顺序 先进来的后出去
lst = [r'D:\sylar\s15',] # 列表的第一个目录就是我要统计的目录
size_sum = 0
while lst:
path = lst.pop()
path_list = os.listdir(path)
for name in path_list:
abs_path = os.path.join(path,name)
if os.path.isdir(abs_path):
lst.append(abs_path)
else:
size_sum += os.path.getsize(abs_path)
print(size_sum)
序列化 模块
什么是序列化? 将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化 .
比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给?
现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。
但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。
你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢?
没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串,
但是你要怎么把一个字符串转换成字典呢?
聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。
eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。
BUT!强大的函数有代价。安全性是其最大的缺点。
想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。
所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)
为什么要有序列化模块
序列化优势:

1. json 模块
需要导入 : import json
dumps loads 在内存中做数据的转换 :
json.dumps() 数据类型 转成 字符串 (序列化)
json.loads() 字符串 转成 数据类型 (反序列化)
import json
dic = {'key' : 'value','key2' : 'value2'}
ret = json.dumps(dic) # 序列化 转成字符串
print(dic,type(dic))
print(ret,type(ret))
# {'key': 'value', 'key2': 'value2'} <class 'dict'> #正常情况下字典中的k和v,如果是字符串类型用单引号
# {"key": "value", "key2": "value2"} <class 'str'> #变成了双引号 字典为字符串类型了
res = json.loads(ret) # 反序列化 又转回字典
print(res,type(res))
#{'key': 'value', 'key2': 'value2'} <class 'dict'>
注意的问题 :
json 在所有的语言之间都通用 : json序列化的数据 在python上序列化了 那在java中也可以反序列化
能够处理的数据类型是非常有限的仅支持 : 字符串 列表 字典 数字
其中字典中的key只能是字符串
# 问题1 反序列化后,key变成了字符串的类型, 反序列化失败 dic = {1 : 'value',2 : 'value2'} ret = json.dumps(dic) # 序列化 print(dic,type(dic)) print(ret,type(ret)) res = json.loads(ret) # 反序列化 print(res,type(res)) # {1: 'value', 2: 'value2'} <class 'dict'> # {"1": "value", "2": "value2"} <class 'str'> # {'1': 'value', '2': 'value2'} <class 'dict'> # 问题2 反序列化后,元组成了列表 反序列化失败 dic = {1 : [1,2,3],2 : (4,5,'aa')} ret = json.dumps(dic) # 序列化 print(dic,type(dic)) print(ret,type(ret)) res = json.loads(ret) # 反序列化 print(res,type(res)) # {1: [1, 2, 3], 2: (4, 5, 'aa')} <class 'dict'> # {"1": [1, 2, 3], "2": [4, 5, "aa"]} <class 'str'> # {'1': [1, 2, 3], '2': [4, 5, 'aa']} <class 'dict'> # 问题3 不支持set集合 s = {1,2,'aaa'} json.dumps(s) # TypeError: Object of type 'set' is not JSON serializable # 问题4 key 必须是字符串类型 json.dumps({(1,2,3):123}) # TypeError: keys must be a string
dump 和 load 直接将数据类型写入文件, 直接从文件中读出数据类型
json.dump() 数据类型 写入 文件 (序列化)
json.load() 文件 读出 数据类型 (反序列化)
# dump load 是直接操作文件的 # 文件中写入字典 dic = {'key1' : 'value1','key2' : 'value2'} with open('json_file','a') as f: json.dump(dic,f) # 字典,文件句柄 # 文件中读取字典 with open('json_file','r') as f: dic = json.load(f) # 文件句柄 print(dic.keys())
不支持连续的读取 json.load()只能取第一个字典,当文件存在多个字典的时候
# 问题5 不支持连续的存 取 dic = {'key1' : 'value1','key2' : 'value2'} with open('json_file','a') as f: json.dump(dic,f) json.dump(dic,f) json.dump(dic,f) # 文件中写入了 3 个字典 # {"key1": "value1", "key2": "value2"}{"key1": "value1", "key2": "value2"}{"key1": "value1", "key2": "value2"} with open('json_file','r') as f: dic = json.load(f) # load读取, 只能读取一个字典,该字典可以是嵌套的 # 文件中若有多个字典,读取时会报错 print(dic.keys())
其他需要注意的问题 :
Serialize obj to a JSON formatted str.(字符串表示的json对象) Skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。) If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. sort_keys:将数据根据keys的值进行排序。 To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used. 其他参数说明
import json f = open('file','w') json.dump({'国籍':'中国'},f) ret = json.dumps({'国籍':'中国'}) f.write(ret+'\n') json.dump({'国籍':'美国'},f,ensure_ascii=False) ret = json.dumps({'国籍':'美国'},ensure_ascii=False) f.write(ret+'\n') f.close() ensure_ascii关键字参数
格式化输出 : 但是由于一般情况下,序列化是为了传输,一般不会用来看,可以不用格式化
import json data = {'username':['李华','二愣子'],'sex':'male','age':16} json_dic2 = json.dumps(data,sort_keys=True,indent=4,separators=(',',':'),ensure_ascii=False) print(json_dic2) # { # "age":16, # "sex":"male", # "username":[ # "李华", # "二愣子" # ] # }
2. pickle 模块
pickle 模块 和 jason 模块差不多,也是用于序列化和反序列化的, 同样存在dumps loads dump load
不同点:
1) 支持python中几乎所有的数据类型, 序列化的结果只能是字节
dic = {(1,2,3):{'a','b'},1:'abc'}
ret = pickle.dumps(dic)
print(ret)
print(pickle.loads(ret))
# b'\x80\x03}q\x00(K\x01K\x02K\x03\x87q.....
# {(1, 2, 3): {'a', 'b'}, 1: 'abc'}
2) 只能在python中使用
3) 在和文件操作的时候,需要用 rb wb ab 模式打开文件,
dic = {(1,2,3):{'a','b'},1:'abc'}
# dump
with open('pickle_file','wb') as f:
pickle.dump(dic,f)
# load
with open('pickle_file','rb') as f:
ret = pickle.load(f)
print(ret,type(ret))
4) 可以多次 dump 和 多次 load
多次load时, 文件中有多个字典时, 要循环取出
# 写 dic = {(1,2,3):{'a','b'},1:'abc'} dic1 = {(1,2,3):{'a','b'},2:'abc'} dic2 = {(1,2,3):{'a','b'},3:'abc'} with open('pickle_file','wb') as f: pickle.dump(dic, f) pickle.dump(dic1, f) pickle.dump(dic2, f) #写入了3次 # 读 (一般不采用此种方法读取) with open('pickle_file','rb') as f: ret = pickle.load(f) print(ret,type(ret)) ret = pickle.load(f) print(ret,type(ret)) ret = pickle.load(f) print(ret, type(ret)) ret = pickle.load(f) # 读取的次数不容易控制 print(ret, type(ret)) # 读取4次 ,报错 EOFError: Ran out of input # 异常处理后 读 with open('pickle_file','rb') as f: while True: try: ret = pickle.load(f) print(ret,type(ret)) except EOFError: break


浙公网安备 33010602011771号