Python基础-常用模块

第1章 模块介绍

1.1 模块的定义

一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。

1.2 模块的类别

  1. 使用python编写的代码(.py文件);
  2. 已被编译为共享库或DLL的C或C++扩展;
  3. 包好一组模块的包;
  4. 使用C编写并链接到python解释器的内置模块。

1.3 模块导入原理

Python解释器会先从sys.modules里查看模块是否已经被导入,如果没有被导入,就依据sys.path路径取寻找模块,找到了就导入;如果sys.modules已经有了模块的名称,则直接使用该模块,故即使程序中多次import同一个模块程序也仅导入该模块一次。

1.4 模块使用小结

1.4.1 模块使用小结

  • 编写代码中导入模块的顺序:内置模块 —> 扩展模块 —> 自定义模块
  • 尽量在程序的最上方导入所有的模块
  • 同一个文件中模块只能被导入一次:moudles
  • 模块的导入路径:path
import sys
print(sys.modules.keys())
print(sys.path)

1.4.2 import模块小结

  • import 模块名:模块名/变量名使用自己的命名空间,和本文件中的变量名完全不冲突
  • import 模块名 as 重命名的模块名:可以提高代码的兼容性
  • import 模块1,模块2 (不推荐使用此方法)
# as提高代码兼容性示例
if 数据库 == ‘oracle’:
    import oracle as db
elif 数据库 == ‘mysql’:
    import mysql as db
# 连接数据库   db.connect
# 登录认证
# 增删改查
# 关闭数据库

# 同时导入多个模块示例
import time,sys,os

# 导入自定义模块及模块调用示例
import damo
damo.read()
damo.read2()

1.4.3 from import小结

  • from 模块名 import 变量名:直接使用变量名就可以完成操作,如果本文件中有相同的变量名会发生冲突
  • from 模块名 import 变量名字 as 重命名变量名
  • from 模块名 import 变量名1,变量名2
  • from 模块名 import *:将模块中的所有变量名都放到内存中,如果本文件中有相同的变量名会发生冲突(不推荐使用此方法)
  • from 模块名 import * 和 __all__ 是一对:没有__all__这个变量,就会导入所有的名字,如果有all就只导入all列表中的名字

【示例】:

# damo.py:

__all__ = ['read', 'read2']
money = 100

def login():
    print('正在执行登录程序')

def read():
    print('in read1',money)

def read2():
    print('in read2')

if __name__ == '__main__':
    ret = login()
print(ret)

# 模块导入py文件
from damo import *
read()
read2()
print(money)

【运行结果】:

in read1 100
in read2
Traceback (most recent call last):
  File "D:/WorkSpace/Python/python_study/week11/模块的导入.py", line 33, in <module>
    print(money)
NameError: name 'money' is not defined

1.4.4 __name__变量

在模块中 有一个变量__name__,当我们直接执行这个模块的时候,__name__ == ‘__main__’;当我们执行其他模块,在其他模块中引用这个模块的时候,这个模块中的__name__ == ‘模块的名字’。

# damo.py:
if __name__ == '__main__':      # __name__ == '__main__'
    ret = login()
print(ret)
# 模块导入py文件
import damo
print(damo.__name__)            # damo

第2章 正则表达式

Tips:正则表达式测试网站:http://tool.chinaz.com/regex/

2.1 字符匹配

元字符 匹配内容
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组
[…] 匹配字符组中的字符
[^…] 匹配除了字符组中字符的所有字符

2.2 量词匹配

量词 用法说明
* 重复零次或更多次
+ 重复一次或更多次
重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

Tips:前面的*,+, 等都是贪婪匹配,也就是尽可能匹配,后面加 号使其变成惰性匹配。

2.3 位置匹配

位置符号 用法说明
. 匹配任意一个字符
^ 匹配以什么开头的字符串
$ 匹配以什么结尾的字符串

2.4 字符集匹配

正则 待匹配字符 匹配
结果
说明
李[杰莲英二棍子]* 李杰和李莲英和李二棍子 李杰
李莲英李二棍子
表示匹配”李”字后面[杰莲英二棍子]的字符任意次
李[^和]* 李杰和李莲英和李二棍子 李杰
李莲英李二棍子
表示匹配一个不是”和”的字符任意次
[\d] 456bdha3 4

5

6

3

表示匹配任意一个数字,匹配到4个结果
[\d]+ 456bdha3 456

3

表示匹配任意个数字,匹配到2个结果

2.5 分组 ()与 或 |[^]

正则 待匹配字符 匹配
结果
说明
^[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 现在不会匹配错误的身份证号了
()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ 110105199812067023 110105199812067023 表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14}

2.6 转义符 \

在正则表达式中,有很多有特殊意义的是元字符,比如\n和\s等,如果要在正则中匹配正常的”\n”而不是”换行符”就需要对”\”进行转义,变成’\\’。

在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。所以如果匹配一次”\n”,字符串中要写成’\\n’,那么正则里就要写成”\\\\n”,这样就太麻烦了。这个时候我们就用到了r’\n’这个概念,此时的正则是r’\\n’就可以了。

正则 待匹配字符 匹配

结果

说明
\n \n False 因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配
\\n \n True 转义\之后变成\\,即可匹配
“\\\\n” ‘\\n’ True 如果在python中,字符串中的’\’也需要转义,所以每一个字符串’\’又需要转义一次
r’\\n’ r’\n’ True 在字符串之前加r,让整个字符串不转义

2.7 贪婪匹配

贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配。

正则 待匹配字符 匹配
结果
说明
<.*> <script>…<script> <script>…<script> 默认为贪婪匹配模式,会匹配尽量长的字符串
<.* > r’\d’ <script>

<script>

加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
  • 几个常用的非贪婪匹配Pattern

* 重复任意次,但尽可能少重复

+ 重复1次或更多次,但尽可能少重复

重复0次或1次,但尽可能少重复

{n,m} 重复n到m次,但尽可能少重复

{n,} 重复n次以上,但尽可能少重复

  • .* 的用法:

. 是任意字符

* 是取 0 至 无限长度

是非贪婪模式。

何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:

.* x 就是取前面任意长度的字符,直到一个x出现

第3章 re模块

3.1 检测手机号

【示例】:

import re
phone_number = input('请输入你的手机号:')
if re.match('0 (13|14|15|17|18|19)[0-9]{9}',phone_number):
    print('这是合法的手机号')
else:
print('这不是合法的手机号')

【运行结果】:

请输入你的手机号:13196233595
这是合法的手机号

3.2 findall方法

【示例】:返回所有满足匹配条件的结果,放在列表里

import re
ret = re.findall('[a-z]+','hello world!')
print(ret)

【运行结果】:

['hello', 'world']

3.3 search方法

【示例】:从前往后,找到一个就返回,返回的变量需要调用group才能拿到结果;如果没有找到,那么返回None,调用group会报错。

import re
ret=re.search('e','hello world!')
if ret:
    print(ret.group())

【运行结果】:

e

3.4 match方法

【示例】:match是从头开始匹配,如果正则规则从头开始可以匹配上,就返回一个变量,匹配的内容需要用group才能显示;如果没匹配上,就返回None,调用group会报错。

import re
ret = re.match('[a-z]+','hello world!')
if ret:
    print(ret.group())

【运行结果】:

hello

3.5 split方法

【示例】:先按’a’分割得到”和’bcd’,在对”和’bcd’分别按’b’分割,分割的字符不保留。

import re
ret = re.split('[ab]','abcd')
print(ret)

【运行结果】:

['', '', 'cd']

3.6 sub方法

【示例】:将数字替换成’H’,参数1表示只替换1个。

import re
ret = re.sub('\d','H','abc1def2ghi3')
print(ret)
ret = re.sub('\d','H','abc1def2ghi3',1)
print(ret)

【运行结果】:

abcHdefHghiH
abcHdef2ghi3

3.7 subn方法

【示例】:将数字替换成’H’,返回元组(替换的结果,替换了多少次)

import re
ret = re.subn('\d','H','abc1def2ghi3')
print(ret)

【运行结果】:

('abcHdefHghiH', 3)

3.8 compile方法

【示例】:将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字

import re
obj = re.compile('\d{3}')
ret = obj.search('abc123eeee')
print(ret.group())
ret = obj.search('abcashgjgsdghkash456eeee3wr2')
print(ret.group())

【运行结果】:

123
456

3.9 finditer方法

【示例】:finditer返回一个存放匹配结果的迭代器

import re
ret = re.finditer('\d','ds3sy4784a')
print(ret)
for i in ret:
    print(i.group())

【运行结果】:

<callable_iterator object at 0x007A2470>
3
4
7
8
4

3.10 特殊用法

【示例】:

import re

ret = re.findall('(www|blog).leonshadow.com', 'blog.leonshadow.com')
print(ret)  # ['blog'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

ret = re.findall('( :www|blog).leonshadow.com', 'blog.leonshadow.com')
print(ret)  # ['blog.leonshadow.com']

【示例】:

import re

ret=re.split("\d+","abc3def4ghij")
print(ret) # 结果 : ['abc', 'def', 'ghij']

ret=re.split("(\d+)","abc3def4ghij")
print(ret) # 结果 : ['abc', '3', 'def', '4', 'ghij']

第4章 collections模块

4.1 namedtuple方法

【示例】:

from collections import namedtuple
Point = namedtuple('point',['x','y','z'])
p1 = Point(1,2,3)
p2 = Point(3,2,1)
print(p1.x)
print(p1.y)
print(p1,p2)

【运行结果】:

1
2
point(x=1, y=2, z=3) point(x=3, y=2, z=1)

4.2 queue方法

【示例】:

import queue
q = queue.Queue()
q.put([1,2,3])
q.put(5)
q.put(6)
print(q)
print(q.get())
print(q.get())
#print(q.get())
#print(q.get())   # 当全部数据取出后,再取出的话会阻塞
print(q.qsize())

【运行结果】:

<queue.Queue object at 0x02A22470>
[1, 2, 3]
5
1

4.3 deque方法

【示例】:

from collections import deque
dq = deque([1,2])
dq.append('a')
dq.appendleft('b')
dq.insert(2,3)
print(dq.pop())
print(dq.pop())
print(dq.popleft())
print(dq)

【运行结果】:

a
2
b
deque([1, 3])

4.4 OrderedDict方法

【示例】:

from collections import OrderedDict
od = OrderedDict([('a',1),('c',3),('b',2)])
print(od)
print(od['a'])
for k in od:
    print(k))

【运行结果】:

OrderedDict([('a', 1), ('c', 3), ('b', 2)])
1
a
c
b

4.5 defaultdict方法

【示例】:

from collections import defaultdict
d = defaultdict(lambda : 5)
print(d['k'])

【运行结果】:

5

第5章 time模块

5.1 时间格式分类

5.1.1 格式化时间

格式化的时间字符串,如‘1999-12-06’(字符串)
%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 当前时区的名称
%% %号本身

5.1.2 时间戳时间

时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量(float时间)

5.1.3 结构化时间

计算用的时间格式,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

5.1.4 时间格式小结

时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的。

5.2 三种时间格式之间的转换

5.3 sleep和time方法

【示例】:

import time
print(time.time())
time.sleep(2)
print('睡了一会')
print(time.time())

【运行结果】:

1538012335.406742
睡了一会
1538012337.4332068

5.4 格式化时间

【示例】:

import time
print(time.strftime("%Y-%m-%d %a %H:%M:%S"))
print(time.strftime("%Y/%m/%d %H:%M:%S"))
print(time.strftime("%m-%d %H:%M:%S"))
print(time.strftime("%H:%M:%S"))
print(time.strftime("%H:%M"))

【运行结果】:

2018-09-27 Thu 09:49:30
2018/09/27 09:49:30
09-27 09:49:30
09:49:30
09:49

5.5 结构化时间

【示例】:

import time
struct_time = time.localtime()
print(struct_time)
print(struct_time.tm_year)

【运行结果】:

time.struct_time(tm_year=2018, tm_mon=9, tm_mday=27, tm_hour=9, tm_min=53, tm_sec=7, tm_wday=3, tm_yday=270, tm_isdst=0)
2018

5.6 时间转换

【示例】:

import time

t = time.time()
print(t)
print(time.localtime(t))
print(time.gmtime(t))

print(time.mktime(time.localtime(t)))
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(t)))

print(time.asctime())

【运行结果】:

1538013454.5920074
time.struct_time(tm_year=2018, tm_mon=9, tm_mday=27, tm_hour=9, tm_min=57, tm_sec=34, tm_wday=3, tm_yday=270, tm_isdst=0)
time.struct_time(tm_year=2018, tm_mon=9, tm_mday=27, tm_hour=1, tm_min=57, tm_sec=34, tm_wday=3, tm_yday=270, tm_isdst=0)
1538013454.0
2018-09-27 09:57:34
Thu Sep 27 09:57:34 2018

第6章 random模块

6.1 随机方法示例

【示例】:

import random

print(random.random())                      # 生成大于0且小于1之间的小数
print(random.uniform(1,3))                  # 生成大于1小于3的小数

print(random.randint(1,5))                  # 大于等于1且小于等于5之间的整数
print(random.randrange(1,10,2))             # 大于等于1且小于10之间的奇数

print(random.choice([1,'23',[4,5]]))        # 随机选择一个返回,1或者23或者[4,5]
print(random.sample([1,'23',[4,5]],2))      # 随机选择多个返回,返回的个数为函数的第二个参数,列表元素任意2个组合

item = [1,3,5,7,9]                          # 打乱列表顺序
random.shuffle(item)
print(item)
random.shuffle(item)
print(item)

【运行结果】:

0.13631001122108544
2.4949036192504543
1
5
1
[1, [4, 5]]
[9, 5, 1, 3, 7]
[9, 3, 7, 1, 5]

6.2 随机验证码

【示例】:

import random
def v_code():
    code = ''
    for i in range(5):
        num = random.randint(0,9)
        alf = chr(random.randint(65,90))
        add = random.choice([num,alf])
        code="".join([code,str(add)])
    return code

print(v_code())

【运行结果】:

1MK4P

第7章 os模块

7.1 os模块常用方法

import 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
path = 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的大小

7.2 获取当前路径及改变路径

【示例】:

import os
print(os.getcwd())
os.chdir(r'D:\WorkSpace\python_study')
print(os.getcwd())

【运行结果】:

D:\WorkSpace\python_study\week10
D:\WorkSpace\python_study

7.3 拼接路径及查看文件信息

【示例】:

import os
print(os.path.split(os.getcwd()))
print(os.path.join(r'C:\Users\Administrator','user','local'))
print(os.getcwd())
print(os.path.getsize(os.path.join(os.getcwd(),'os模块.py')))

print(os.listdir(r'D:\WorkSpace\python_study\week10'))
print(os.stat('os模块.py'))

【运行结果】:

('D:\\WorkSpace\\python_study', 'week10')
C:\Users\Administrator\user\local
D:\WorkSpace\python_study\week10
3356
['collections模块.py', 'os模块.py', 'random模块.py', 're模块.py', 'time模块.py']
os.stat_result(st_mode=33206, st_ino=9570149208163378, st_dev=1084377104, st_nlink=1, st_uid=0, st_gid=0, st_size=3356, st_atime=1538015558, st_mtime=1538015558, st_ctime=1538015558)
Tips: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)是创建时间(详细信息参见平台的文档)。

7.4 获取系统相关信息

【示例】:

import os
print(os.sep)         # 打印操作系统分割符,跨平台时使用
print(os.environ)     # 获取系统环境变量

【运行结果】:

\
environ({'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\PinMing\\AppData\\Roaming'...
  • 跨平台操作相关方法:
os.sep          # 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep      # 输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"
os.pathsep      # 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name         # 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'

第8章 sys模块

Tips:sys模块是与python解释器交互的一个接口。

8.1 sys模块常用方法

sys.argv           # 命令行参数List,第一个元素是程序本身路径
sys.exit(n)        # # 退出程序,正常退出时exit(0),错误退出sys.exit(1)
sys.version        # 获取Python解释程序的版本信息
sys.path           # 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform       # 返回操作系统平台名称

8.2 异常处理

【示例】:

import sys
try:
    sys.exit(1)
except SystemExit as e:
print(e)

第9章 序列化模块

9.1 序列化定义

将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化。

9.2 序列化的目的

1、以某种存储形式使自定义对象持久化;

2、将对象从一个地方传递到另一个地方;

3、使程序更具维护性。

9.3 序列化的两个主要模块

  • json:用于字符串和python数据类型间进行转换。
  • pickle:用于python特有的类型和python的数据类型间进行转换。

9.4 json模块

Json是通用的序列化格式,但是只有很少的一部分数据类型能够通过json转化成字符串(数字,字符串,列表,字典,元组)。

9.4.1 dumps/loads方法

【示例】:

import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
print(type(dic),dic)
str_dic = json.dumps(dic)               # 序列化:将一个字典转换成一个字符串
print(type(str_dic),str_dic)            # json转换完的字符串类型的字典中的字符串是由""表示的

【运行结果】:

<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
<class 'str'> {"k1": "v1", "k2": "v2", "k3": "v3"}

【示例】:

import json
dic2 = json.loads(str_dic)
print(type(dic2),dic2)

【运行结果】:

<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

9.4.2 dump/load方法

Tips:此方法不可一行一行的写入和读出,若想一行一行的写入和读出需借助dumps/loads实现。

【示例】:

import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f)        # dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()

【运行结果】:

json_file:
{"k1": "v1", "k2": "v2", "k3": "v3"}

【示例】:

import json
f = open('json_file')
dic2 = json.load(f)
f.close()
print(type(dic2),dic2)

【运行结果】:

<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

9.4.3 一行一行写入和读出文件

【示例】:

import json

l = [{'k1':'v1'},{'k2':'v2'},{'k3':'v3'}]
f = open('json_file','w')

for dic in l:
    str_dic = json.dumps(dic)
    f.write(str_dic+'\n')
f.close()

f = open('json_file')
l = []

for line in f:
    dic = json.loads(line.strip())
    l.append(dic)
f.close()

print(l)

【运行结果】:

[{'k1': 'v1'}, {'k2': 'v2'}, {'k3': 'v3'}]

9.4.4 ensure_ascii关键字

当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。

【示例】:

import json
f = open('json_file','w',encoding='utf8')

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()

【运行结果】:

json_file:
{"\u56fd\u7c4d": "\u4e2d\u56fd"}{"\u56fd\u7c4d": "\u4e2d\u56fd"}
{"国籍": "美国"}{"国籍": "美国"}

9.5 pickle模块

所有的python中的数据类型都可以转化成字符串形式,pickle序列化的内容只有python能理解,且部分反序列化依赖python代码。

pickle模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load (不仅可以序列化字典,列表…可以把python中任意的数据类型序列化)

9.5.1 pickle与json用法的区别

pickle用法与json基本行相同,两点不同:

  • dump/load对文件操作均为位操作,即均需使用带‘b’的方式打开文件;
  • pickle可以直接一行一行的写入和读取文件。

9.5.2 dumps/loads方法

【示例】:

import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(type(str_dic),dic)

dic2 = pickle.loads(str_dic)
print(dic2)

【运行结果】:

<class 'bytes'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

9.5.3 dump/load方法

【示例】:

import pickle
import time

struct_time1 = time.localtime(1000000000)
struct_time2 = time.localtime(2000000000)

f = open('pickle_file','wb')
pickle.dump(struct_time1,f)
pickle.dump(struct_time2,f)
f.close()

f = open('pickle_file','rb')
struct_time1 = pickle.load(f)
struct_time2 = pickle.load(f)

print(struct_time1.tm_year)
print(struct_time2.tm_year)
f.close()

【运行结果】:

2001
2033

9.6 shelve模块

Python3.x中新的序列化模块,生成序列化句柄,使用句柄直接操作,非常方便,但是可能存在未知bug,不常用。

【示例】:

import shelve

f = shelve.open('shelve_file')
f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'}  #直接对文件句柄操作,就可以存入数据
f.close()

f1 = shelve.open('shelve_file')
existing = f1['key']  #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错
f1.close()

print(existing)

【运行结果】:

{'int': 10, 'float': 9.5, 'string': 'Sample data'}

【示例】:

import shelve

f = shelve.open('shelve_file', flag='r')
existing = f['key']
f.close()

print(existing)

f = shelve.open('shelve_file', flag='r')
existing2 = f['key']
f.close()

print(existing2)

【运行结果】:

{'int': 10, 'float': 9.5, 'string': 'Sample data'}

第10章 hashlib模块

10.1 算法介绍

Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

10.2 摘要算法特点

  1. 不管算法多么不同,摘要的功能始终不变
  2. 对于相同的字符串使用同一个算法进行摘要,得到的值总是不变的
  3. 使用不同算法对相同的字符串进行摘要,得到的值应该不同
  4. 不管使用什么算法,hashlib的方式永远不变

10.3 摘要算法用途

  1. 加密用户名及密码或其他需要加密的字符串
  2. 检查文件的一致性

10.4 摘要算法示例

10.4.1 MD5加密示例

【示例】:

import hashlib
md5 = hashlib.md5()
md5.update(b'123456')
print(md5.hexdigest())

【运行结果】:

e10adc3949ba59abbe56e057f20f883e

10.4.2 sha1加密示例

【示例】:

import hashlib
sha = hashlib.sha1()
sha.update(b'123456')
print(sha.hexdigest())

【运行结果】:

7c4a8d09ca3762af61e59520943dc26494f8941b

10.4.3 用户登录示例

密码加密的解决方案不是通过解密加密后的密码和用户新输入的密码做比对,而是当用户新输入密码之后,直接对输入的密码再次做同样的加密处理后得到的值与加密的密码作比较,相同则判断密码输入正确,不同则密码输入错误。

【示例】:

import hashlib
usr = input("username : ")
pwd = input("password : ")

with open('userinfo') as f:
    for line in f:
        user,password,role = line.split('|')
        md5 = hashlib.md5()
        md5.update(bytes(pwd,encoding='utf-8'))
        md5Pwd = md5.hexdigest()
        if usr == user and md5Pwd == password:
            print('登陆成功')

# userinfo文件:
leon|e10adc3949ba59abbe56e057f20f883e|admin

【运行结果】:

username : leon
password : 123456
登陆成功

10.5 升级加密方式

10.5.1 加盐加密

由于常用口令的MD5值很容易被计算出来,所以要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”。

【示例】:

import hashlib
md5 = hashlib.md5(bytes('盐',encoding='utf-8'))
md5.update(b'123456')
print(md5.hexdigest())

【运行结果】:

970d52d48082f3fb0c59d5611d25ec1e

10.5.2 动态加盐加密

使用用户名或密码的一部分或者直接使用整个用户名和密码作为盐,或再拼接一个固定的复杂的字符串作为盐。

【示例】:

import hashlib
md5 = hashlib.md5(bytes('盐1',encoding='utf-8')+b'username'+b'password'+bytes('盐2',encoding='utf-8'))
md5.update(b'123456')
print(md5.hexdigest())

【运行结果】:

b079e4ab424118dee0765083528c9947

第11章 configparser模块

11.1 configparser模块介绍

该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。

11.2 创建文件

【示例】:

import configparser
config = configparser.ConfigParser()

config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9',
                     'ForwardX11':'yes'
                     }
config['bitbucket.org'] = {'User':'hg'}
config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}

with open('config.ini', 'w') as configfile:
   config.write(configfile)

【运行结果】:

# config.ini文件:
[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes

[bitbucket.org]
user = hg

[topsecret.server.com]
host port = 50022
forwardx11 = no

11.3 查找文件

【示例】:

import configparser
config = configparser.ConfigParser()
#---------------------------查找文件内容,基于字典的形式------------------------------------#
print(config.sections())

config.read('config.ini')
print(config.sections())

print('bytebong.com' in config)
print('bitbucket.org' in config)

print(config['bitbucket.org']["user"])
print(config['DEFAULT']['Compression'])
print(config['topsecret.server.com']['ForwardX11'])

print(config['bitbucket.org'])

for key in config['bitbucket.org']:                 # 注意,有default会默认default的键
    print(key)
print(config.options('bitbucket.org'))              # 同for循环,找到'bitbucket.org'下所有键
print(config.items('bitbucket.org'))                # 找到'bitbucket.org'下所有键值对
print(config.get('bitbucket.org','compression'))    # yes get方法Section下的key对应的value

【运行结果】:

[]
['bitbucket.org', 'topsecret.server.com']
False
True
hg
yes
no
<Section: bitbucket.org>
user
serveraliveinterval
compression
compressionlevel
forwardx11
['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']
[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]
yes

11.4 增删改操作

【示例】:

import configparser
config = configparser.ConfigParser()

config.read('config.ini')
config.add_section('yuan')

config.remove_section('bitbucket.org')
config.remove_option('topsecret.server.com',"forwardx11")

config.set('topsecret.server.com','k1','11111')
config.set('yuan','k2','22222')

config.write(open('config2.ini', "w"))

【运行结果】:

# config2.ini文件:
[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes

[topsecret.server.com]
host port = 50022
k1 = 11111

[yuan]
k2 = 22222

第12章 logging模块

12.1 logging模块介绍

默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。

12.2 basicconfig模式

12.2.1 优缺点对比

  • 优点:写法简单
  • 缺点:能做的事情相对少,中文会产生乱码问题,不能同时往文件和屏幕上输出

12.2.2 详细配置参数

logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:

%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息

12.2.3 配置示例

【示例】:

import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

【运行结果】:

WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

【示例】:

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='test.log',
                    filemode='w')

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

【运行结果】:

# test.log文件:
Sat, 06 Oct 2018 10:18:27 logging   .py[line:28] DEBUG debug message
Sat, 06 Oct 2018 10:18:27 logging   .py[line:29] INFO info message
Sat, 06 Oct 2018 10:18:27 logging   .py[line:30] WARNING warning message
Sat, 06 Oct 2018 10:18:27 logging   .py[line:31] ERROR error message
Sat, 06 Oct 2018 10:18:27 logging   .py[line:32] CRITICAL critical message

12.3 log对象模式

12.3.1 log对象模式介绍

logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过fh.setLevel(logging.Debug)单对文件流设置某个级别。

12.3.2 优缺点对比

  • 优点:能做的事情相对多,让程序充分解耦,让程序变得高可定制
  • 缺点:写法稍微有点复杂

12.3.3 配置示例

【示例】:

import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
formatter2 = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s [line:%(lineno)d] : %(message)s')

fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ch.setFormatter(formatter2)

logger.addHandler(fh)       # logger对象可以添加多个fh和ch对象
logger.addHandler(ch)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('警告错误')
logger.error('logger error message')
logger.critical('logger critical message')

【运行结果】:

# 控制台输出:
2018-10-06 10:22:44,341 - root - WARNING [line:54] : 警告错误
2018-10-06 10:22:44,341 - root - ERROR [line:55] : logger error message
2018-10-06 10:22:44,341 - root - CRITICAL [line:56] : logger critical message
# test.log文件:
2018-10-06 10:22:44,341 - root - WARNING - 警告错误
2018-10-06 10:22:44,341 - root - ERROR - logger error message
2018-10-06 10:22:44,341 - root - CRITICAL - logger critical message

第13章 包的介绍

13.1 包的定义

包是一种通过使用‘.模块名’来组织python模块名称空间的方式。

13.2 包的本质

  1. 无论是import形式还是..import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法。
  2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含py文件的目录)。
  3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的py,导入包本质就是在导入该文件。

Tips:注意

在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错;

创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块。

13.3 包的注意事项

  1. 关于包相关的导入语句也分为import和from … import …两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如subitem.subsubitem,但都必须遵循这个原则。
  2. 对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
  3. 对比import item 和from item import name的应用场景:如果我们想直接使用name那必须使用后者

13.4 __init__.py文件

不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码。

13.5 包的使用方式

13.5.1 示例文件目录结构

【原始结构】:

13.5.2 import方式

【示例】:原始结构

import glance.api.policy
glance.api.policy.get()

import glance.api.policy as policy
policy.get()

【运行结果】:

from policy.py
from policy.py

13.5.3 from…import方式

Tips:需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法。

【示例】:原始结构

from week11.glance.api import policy
policy.get()

【运行结果】:

from policy.py

【变更1后结构】:

【示例】:变更1后结构

import sys
print(sys.path)
from dir.glance.api import policy
policy.get()

【运行结果】:

['D:\\WorkSpace\\Python\\python_study\\week11', 'D:\\WorkSpace\\Python\\python_study'...
from policy.py

【示例】:变更1后结构

import sys
print(sys.path)
sys.path.insert(0,'D:\\WorkSpace\\Python\\python_study\\week11\\dir')
print(sys.path)
from glance.api import policy
policy.get()

【运行结果】:

['D:\\WorkSpace\\Python\\python_study\\week11', 'D:\\WorkSpace\\Python\\python_study'...
['D:\\WorkSpace\\Python\\python_study\\week11\\dir', 'D:\\WorkSpace\\Python\\python_study\\week11',...
from policy.py

【变更2后结构】:绝对路径导入

Tips:绝对路径

使用绝对路径不管在包内部还是外部,导入了就能用;

不能挪动,但是直观。

【示例】:变更2后结构

import glance
glance.db.models.register_models('mysql')

【运行结果】:

from models.py:  mysql

【示例】:变更2后结构

import glance
glance.db.models.register_models('mysql')

from glance import db
db.models.register_models('mysql')

【运行结果】:

from models.py:  mysql
from models.py:  mysql

【变更3后结构】:相对路径导入

Tips:相对路径

可以随意移动包,只要能找到包的位置,就可以使用包里的模块;

包里的模块如果想使用其它模块的内容只能使用相对路径;

使用了相对路径就不能在包内直接执行了。

【示例】:变更3后结构

import glance
glance.db.models.register_models('mysql')

from glance import db
db.models.register_models('mysql')

【运行结果】:

from models.py:  mysql
from models.py:  mysql

第14章 软件开发目录结构规范

第15章 异常处理

程序一旦发生错误,就从错误的位置停下来了,不在继续执行后面的内容,此时使用try和except就能处理异常。

15.1 异常分类

  • 语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)
  • 逻辑错误(逻辑错误)

15.2 异常种类

15.2.1 常用异常

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的

15.2.2 其他异常

ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError

15.3 异常处理格式

15.3.1 代码格式

try:
     被检测的代码块
except 异常类型:
     try中一旦检测到异常,就执行这个位置的逻辑

15.3.2 详细说明

  • try:是我们需要处理的代码
  • except:后面跟一个错误类型 当代码发生错误且错误类型符合的时候 就会执行except中的代码,except支持多分支
  • Exception:完成异常处理,有了万能的处理机制仍然需要把能预测到的问题单独处理,并且单独处理的所有内容都应该写在万能异常之前
  • else:没有异常的时候执行else中的代码
  • finally:不管代码是否异常,都会执行。finally和return相遇的时候 依然会执行;函数里做异常处理用,不管是否异常去做一些收尾工作

15.3.3 代码示例

【示例】:

try:
    # 1/0
    # name
    # 2+'3'
    # [][3]
    # {}['k']
    ret = int(input('number >>>'))
    print(ret*'*')
except ValueError:
    print('输入的数据类型有误')
except Exception as error:  # 万能处理尽量加上重命名打印出问题,让程序员知道是什么问题导致的异常
    print('你错了,老铁',error)
else:
    print('没有异常的时候执行else中的代码')
finally:
        print('执行finally了')
print('===========')

【运行结果】:

number >>> a
输入的数据类型有误
执行finally了
===========

【运行结果】:

number >>> 1
*
没有异常的时候执行else中的代码
执行finally了
===========

【示例】:

try:
    1/0
    # name
    # 2+'3'
    # [][3]
    # {}['k']
    ret = int(input('number >>>'))
    print(ret*'*')
except ValueError:
    print('输入的数据类型有误')
except Exception as error: # 万能处理尽量加上重命名打印出问题,让程序员知道是什么问题导致的异常
    print('你错了,老铁',error)
else:
    print('没有异常的时候执行else中的代码')
finally:
        print('执行finally了')
print('===========')

【运行结果】:

你错了,老铁
执行finally了
===========

15.4 异常处理的好处

try..except这种异常处理机制就是取代if那种方式,让程序在不牺牲可读性的前提下增强健壮性和容错性;异常处理中为每一个异常定制了异常类型(python中统一了类与类型,类型即类),对于同一种异常,一个except就可以捕捉到,可以同时处理多段代码的异常(无需‘写多个if判断式’)减少了代码,增强了可读性。

15.4.1 主要的好处小结

  1. 把错误处理和真正的工作分开来;
  2. 代码更易组织,更清晰,复杂的工作任务更容易实现;
  3. 更安全,不至于由于一些小的疏忽而使程序意外崩溃了。

15.5 异常处理的使用场景

try…except应该尽量少用,因为它本身就是附加给程序的一种异常处理的逻辑,与主要的工作没有关系的;这种东西加的多了,会导致代码可读性变差,只有在有些异常无法预知的情况下,才应该加上try…except,其他的逻辑错误应该尽量修正。

温馨提示:本文最后更新于2022-12-20 20:57:46,已超过465天没有更新。某些文章具有时效性,若文章内容或图片资源有错误或已失效,请联系站长。谢谢!
转载请注明本文链接:https://blog.leonshadow.cn/763482/1274.html
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享