1.模块
1.1什么是模块
一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀;
模块分为:
- 内置模块(内部定义的如time,os,sys等)
- 第三方模块(需要安装)
- 自定义模块(自己定义的)
1.2为什么要使用模块
如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用,
2.模块的使用
2.1导入一个模块
- 导入一个系统模块;并引用这个模块;
import time
print(time.time())
输出:
1487571343.8582766
2.2自定义一个模块并导入:
1.模块就是一个包含了python定义和声明的文件,所以先创建一个cal.py的文件;
[root@linux-node1 ~]# cat cal.py
print("ok1")
def add(x, y):
return x+y
def sub(x, y):
return x-y
print("ok2")
2.在另一个文件test.py中使用import导入cal.py文件(在调用时需要加上cal.前缀)
语法:import cal.py (默认py不写)
[root@linux-node1 ~]# cat test.py
import cal
print(cal.sub(4, 5))
print(cal.add(4, 5))
输出:
ok1
ok2
-1
9
3.在文件test.py中导入单个模块(在使用的时候,不需要加cal前缀);
语法:from cal.py import 模块
[root@linux-node1 ~]# cat test.py
from cal import add
from cal import sub
print(sub(4, 5))
print(add(4, 5))
输出:
ok1
ok2
-1
9
4.在文件test.py中导入所有模块(不建议这么使用,不能确定到底导入了什么模块,会产生模块覆盖);
语法:from cal.py import *
[root@linux-node1 ~]# cat test.py
from cal import *
print(sub(4, 5))
print(add(4, 5))
输出:
ok1
ok2
-1
9
5.可以将导入的模块定义一个别名:
语法:import 模块 as 别名
[root@linux-node1 ~]# cat test.py
import cal as abc
print(abc.sub(4, 5))
print(abc.add(4, 5))
输出:
ok1
ok2
-1
9
2.3自定义模块与调用模块不在同一个路径:
1.在解释器和模块之间不在同一个目录,解释器在模块的上一层路径,如何调用模块;
目录结构:
└── 自定义模块
├── __init__.py
├── my_module
│ ├── __init__.py
│ └── cal.py # 被调用者
└── test.py # 调用者
语法:
from 目录路径 import 被调用模块
[root@linux-node1 ~]# cat test.py
from my_module import cal
print(cal.add(4, 5))
输出:
ok1
ok2
-1
9
常用内置标准模块
- time 时间模块
- timedate 时间模块
- random,string模块(生成随机字符串)
- os模块
- sys模块
- json & pickle 模块
- logging模块
1.时间模块
1.1导入时间模块
import time
1.2当前时间的时间戳
print(time.time())
输出:
1487762678.2732341
1.3返回与utc时间的时间差,以秒计算
print(time.altzone)
输出:
-32400
1.4返回时间格式
print(time.asctime())
输出:
"Wed Feb 22 19:15:04 2017"
1.5返回本地时间 的struct time对象格式
print(time.localtime())
输出:
time.struct_time(tm_year=2017, tm_mon=2, tm_mday=22, tm_hour=19, tm_min=9, tm_sec=35, tm_wday=2, tm_yday=53, tm_isdst=0)
可以调用
f = time.localtime()
print(f.tm_year,f.tm_mon)
输出:
2017 2
1.6返回utc时间的struc时间对象格式
print(time.gmtime())
输出:
time.struct_time(tm_year=2017, tm_mon=2, tm_mday=22, tm_hour=11, tm_min=19, tm_sec=54, tm_wday=2, tm_yday=53, tm_isdst=0)
print(time.asctime(time.localtime()))
Wed Feb 22 19:22:52 2017
1.7自定义时间格式输出:
print(time.strftime("%Y-%m-%d %H:%M:%S"))
输出:
2017-02-22 21:25:48
1.8展现前一天的当前时间:
string_1_struct = time.localtime(time.time()-86400)
print(time.strftime("%Y-%m-%d %H:%M:%S", string_1_struct))
输出:
2017-02-21 21:30:44
1.9将日期字符串转换成struct时间对象格式
string_2_struct = time.strptime("2017-02-22 21:36:12", "%Y-%m-%d %H:%M:%S")
print(string_2_struct)
输出:
time.struct_time(tm_year=2017, tm_mon=2, tm_mday=22, tm_hour=21, tm_min=36, tm_sec=12, tm_wday=2, tm_yday=53, tm_isdst=-1)
1.10将时间的字符串格式转换为时间戳: 将时间字符串---》时间对象---》---》时间戳
string_2_struct = time.strptime("2017-02-22 21:36:12", "%Y-%m-%d %H:%M:%S")
print(time.mktime(string_2_struct))
输出:
1487770572.0
如图:
1.11将时间戳转换为字符串格式: 将时间戳---》时间对象---》时间字符串
zifuchuan = time.gmtime(148770000.0)
print(zifuchuan)
print(time.strftime("%Y-%m-%d %H:%M:%S", zifuchuan))
输出:
time.struct_time(tm_year=1974, tm_mon=9, tm_mday=18, tm_hour=21, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=261, tm_isdst=0)
1974-09-18 21:00:00
2.datetime模块
2.1将当期时间日期打印出来:
print(datetime.datetime.now())
输出:
2017-02-22 22:00:57.059245
2.2将时间戳直接转换为当前时间(详细时间,日期):
print(datetime.datetime.fromtimestamp(time.time()))
print(datetime.date.fromtimestamp(time.time()))
输出:
2017-02-22 22:04:39.177887
2017-02-22
2.3当前时间+3天,-3天,+3小时,-30分钟如下:
print(datetime.datetime.now() + datetime.timedelta(3))
print(datetime.datetime.now() + datetime.timedelta(-3))
print(datetime.datetime.now() + datetime.timedelta(hours=3))
print(datetime.datetime.now() + datetime.timedelta(minutes=-30))
输出:
2017-02-25 22:11:13.730289
2017-02-19 22:11:13.730289
2017-02-23 01:11:13.730289
2017-02-22 22:41:13.730289
2.4修改时间,将时间修改为2016-03-10:
print(datetime.datetime.now().replace(2016, 3, 10))
输出:
2016-03-10 22:13:36.096497
2.5获取前一天的时间:
import datetime
now_time = datetime.datetime.now() # 获取当前时间
yes_time = now_time + datetime.timedelta(days=-1) # 当前时间 -1
yes_time_nyr = yes_time.strftime('%Y-%m-%d') # 截取时间日期部分
print(now_time)
print(yes_time)
print(yes_time_nyr)
输出:
2017-08-30 12:23:59.353665
2017-08-29 12:23:59.353665
2017-08-29
3.random,string模块(生成随机字符串)
3.1在区间数字之间随意抽取一个字符串:
import random,string
print(random.randint(1, 10)) # 会包括最大值 10
print(random.randrange(1, 10)) # 不会包括最大值 10
print(random.randrange(1, 100, 2)) # 取步长为2 奇数值 不包括100
print(random.sample(range(100), 5)) # 随机取5个值
输出:
4
1
[68, 34, 42, 52, 11]
3.2随机验证码:
import random
checkcode = ''
for i in range(5):
current = random.randrange(0, 5)
if current != i:
temp = chr(random.randint(65, 90)) # (65,90)为ASCII 中A-Z的大写字母
else:
temp = random.randint(0, 9) # 从0-9 中间取一个数字
checkcode += str(temp) # 将循环的字符串 拼接 输出
print(checkcode)
输出:
H9J6H
3.3生成字符列:
import random,string
print(string.ascii_uppercase) # 大写字母
print(string.ascii_lowercase) # 小写字母
print(string.ascii_letters) # 大写字母+小写字母
print(string.digits) # 数字 0--9
print(string.hexdigits) # 数字 0--9 + a--f + A--F
print(string.punctuation) # 特殊字符
print(string.printable) # 数字0--9 + 小写 + 大写 + 特殊字符
输出:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
0123456789abcdefABCDEF
!"#$%&'()*+,-./:;<=>?@[]^_`{|}~
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[]^_`{|}~
3.4生成随机验证码二(将大小写字母+数字拼接在一起):
import random,string
abc = string.ascii_letters + string.digits + string.digits
print("".join(random.sample(abc, 6)))
4.OS模块
导入模块:
import os
4.1获取当前用户的工作目录,相当于Linux下的pwd;os.getcwd()
>>> import os
>>> os.getcwd()
'/root'
4.2改变当前脚本的工作目录,相当于Linux下的cd;os.chdir("/var/log")
>>> os.chdir("/var/log")
>>> os.getcwd()
'/var/log'
4.3运行shell命令;os.system("ls")
os.system 只返回执行结果的状态,执行完成后就退出了
>>> os.system("ls")
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
4.4创建联系多级目录;
>>> os.makedirs("d1/d2/d3")
>>> os.system("tree d1")
d1
└── d2
└── d3
4.4.1当目录存在时exist_ok=True不报错
>>> os.makedirs("d1/d2/d3",exist_ok=True)
4.5递归删除多个空目录d1/d2/d3 都会被删除,如果目录不为空报错
>>> os.removedirs("d1/d2/d3")
>>> os.system("tree d1")
d1 [error opening dir]
0 directories, 0 files
0
4.6创建单个目录;
>>> os.mkdir("test")
>>> os.system("tree test")
test
4.7删除单个空目录;相当于linux中的rmdir 目录
>>> os.rmdir("test")
4.8列出指定目录下一级所有文件和子目录
>>> os.listdir(".")
['boot', 'dev', 'proc', 'run', 'sys', 'etc', 'root', 'tmp', 'var', 'usr', 'bin', 'sbin', 'lib', 'lib64', 'home', 'media', 'mnt', 'opt', 'srv', '.autorelabel', 'd1']
4.9删除一个文件,不可以删除目录
>>> os.remove("d1/d2/a")
4.10重新命名 文件/目录
>>> os.rename("d1","d1s")
4.11获取文件的详细信息,创建时间、大小、访问修改时间等
>>> os.stat("d1s")
os.stat_result(st_mode=16877, st_ino=532527, st_dev=2051, st_nlink=3, st_uid=0, st_gid=0, st_size=34, st_atime=1487915706, st_mtime=1487915701, st_ctime=1487915721)
4.11.1获取文件的大小
>>> os.stat("d1s").st_size
34
4.12输出当前系统的路径分隔符“Linux”
>>> os.sep
'/'
4.12.1输出当前系统的路径分隔符“windows”
>>> os.sep
'\'
4.13输出当前平台的换行符“linux”
>>> os.linesep
'
'
4.13.1输出当前平台的换行符“windows”
>>> os.linesep
'
'
4.14输出分隔文件路径的分隔符
>>> os.pathsep
':'
4.15查看当前操作系统的平台platform模块
>>> import platform
>>> platform.platform()
'Linux-3.10.0-327.36.2.el7.x86_64-x86_64-with-centos-7.2.1511-Core'
# 简写
>>> platform.system()
'Linux'
4.16拿到命令的执行结果os.popen
os.popen("df -h").read() 可以拿到命令的执行结果
>>> a = os.popen("df -h").read()
>>> print(a)
文件系统 容量 已用 可用 已用% 挂载点
/dev/sda3 48G 13G 36G 26% /
devtmpfs 903M 0 903M 0% /dev
tmpfs 912M 0 912M 0% /dev/shm
tmpfs 912M 25M 888M 3% /run
tmpfs 912M 0 912M 0% /sys/fs/cgroup
/dev/sda1 197M 182M 15M 93% /boot
tmpfs 183M 0 183M 0% /run/user/0
4.17返回path规范化的绝对路径
import os
print(os.path.abspath(__file__))
输出:
C:UsersDpadPycharmProjectspy_s16day5OS模块os模块.py
4.18将path分隔成目录和文件名的二元组返回
file_path = os.path.abspath(__file__)
print(os.path.split(file_path))
输出:
('C:\Users\Dpad\PycharmProjects\py_s16\day5\OS模块', 'os模块.py')
4.19将path路径的最后一层去除
print(os.path.dirname(file_path))
print(os.path.dirname(os.path.dirname(file_path)))
输出:
C:UsersDpadPycharmProjectspy_s16day5OS模块
C:UsersDpadPycharmProjectspy_s16day5
4.20返回path最后的文件名,如果path以/或结尾,那么返回空
print(os.path.dirname(file_path))
print(os.path.basename(os.path.dirname(file_path)))
输出:
C:UsersDpadPycharmProjectspy_s16day5OS模块
OS模块
4.21如果文件或目录存在,返回True否则返回False
print(os.path.exists(path="os模块.py"))
输出:
True
4.22如果path是绝对路径返回True
print(os.path.isabs("C:/Users/Dpad/PycharmProjects/py_s16/day5/OS模块/os模块.py"))
输出:
True
4.23如果path是一个文件返回True
print(os.path.isfile(path="os模块.py"))
输出:
True
4.24如果path是一个目录返回True
print(os.path.isdir("C:/Users/Dpad/PycharmProjects/py_s16/day5/OS模块/"))
输出:
True
4.25将多个路径拼接成一个路径
print(os.path.join("c:\","a","b"))
输出:
c:a
4.26返回path所指向文件或路径的最后存取时间,和最后修改时间(getatime、getmtime)
print(os.path.getatime("C:/Users/Dpad/PycharmProjects/py_s16/day5/OS模块/"))
print(os.path.getmtime("C:/Users/Dpad/PycharmProjects/py_s16/day5/OS模块/os模块.py"))
输出:
1487921722.556163
1487921722.5354404
4.27得到传入路径的所有子目录以及文件(由于是一个生成器所以需要使用next()取值)
import os
a = os.walk(r"C:Users")
print(next(a))
输出为一个3元素的元组:
# 第一个:元素为 当前传入的目录
# 第二个:元素为 当前传入目录下的所有子目录
# 第三个:元素为 当前传入目录下的所有文件
('C:\Users',
['All Users', 'Default', 'Default User', 'defaultuser0', 'Dpad', 'Public'],
['desktop.ini'])
4.28取得一个目录下的所有子目录的详细路径
import os
def sepash(pash):
a = os.walk(pash)
for pathdir,_,files in a:
# print(pathdir,files)
for file in files:
abspath = r"%s\%s" % (pathdir, file) # 目录拼接操作
print(abspath)
sepash(r"C:UsersDpadPycharmProjectsPyS18day05a")
输出:
C:UsersDpadPycharmProjectsPyS18day05aa1.txt
C:UsersDpadPycharmProjectsPyS18day05aa2.txt
C:UsersDpadPycharmProjectsPyS18day05a11.txt
C:UsersDpadPycharmProjectsPyS18day05a1c1c1.txt
C:UsersDpadPycharmProjectsPyS18day05a22.txt
4.29获取一个文件 a.mp4 的大小
C:UsersDpadPycharmProjectsPyS18 00作业 02-FtpServer>dir
驱动器 C 中的卷没有标签。
卷的序列号是 F2CA-37BC
C:UsersDpadPycharmProjectsPyS18 00作业 02-FtpServer 的目录
2017/08/25 00:17 <DIR> .
2017/08/25 00:17 <DIR> ..
2017/08/19 17:59 88,960,348 a.mp4
C:UsersDpadPycharmProjectsPyS18 00作业 02-FtpServer>python
>>> import os
>>> os.path.getsize("a.mp4")
88960348
5.sys模块
1. 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
import sys
>>> sys.path
['', '/usr/local/lib/python35.zip', '/usr/local/lib/python3.5', '/usr/local/lib/python3.5/plat-linux', '/usr/local/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/site-packages']
2. 过下标的方式获取用户输入的内容
import sys
print(sys.argv)
输出:
C:Usersadmin>python argv.py 1 2 3 4 5 6
['argv.py', '1', '2', '3', '4', '5', '6']
3. copy一个不知存储方式的文件到别处
cat copy.py
import sys
# print(sys.argv)
if len(sys.argv) != 3: # 判断用户给的参数个数
print(""want 3 parameters"Usage: cp [OPTION]... SOURCE DEST")
exit(1)
with open(r"%s" % sys.argv[1],"rb") as ly_r, open(r"%s" % sys.argv[2],"wb") as ly_w:
for i in ly_r:
ly_w.write(i)
4. sed替换文件内的指定内容
cat sed.py
import sys
import os
if len(sys.argv) != 4: # 判断用户给的参数个数
print(""want 4 parameters"Usage: sed.py old_file new_file file_name")
exit(1)
with open(sys.argv[3],"r",encoding="utf-8") as a_r, open("."+sys.argv[3]+"swp","w",encoding="utf-8") as b_w:
for i in a_r:
b = i.replace(sys.argv[1], sys.argv[2]) # 替换用户输入的参数
b_w.write(b)
os.remove(sys.argv[3]) # 删除源文件
os.rename("."+sys.argv[3]+"swp",sys.argv[3]) # 将swp文件重新命名为 源文件
6.json & pickle 模块
用于序列化的两个模块
1.json,用于字符串 和 python数据类型间进行转换
2.pickle,用于python特有的类型 和 python的数据类型间进行转换
Json模块提供了四个功能:dumps、dump、loads、load
pickle模块提供了四个功能:dumps、dump、loads、load
6.1事前案例(序列化和反序列化)
1.将字典存入到文本中:(序列化)
account = {
"id": 622517715,
"zonge": 15000,
"yue": 8000,
"guoqi": "2020-5-21",
"password": "123123"
}
f = open("account.db", "w")
f.write(str(account)) # 文本中存放只能是 bytes 和 字符串str
f.close()
2.在另一个文件中加载字典文件:(反序列化)
f = open("account.db", "r")
account = eval(f.read()) # 加载时将 字符串str 文件转换为 字典dict
print(account)
print(account["id"]) # 打印ID 索引
输出:
{'yue': 8000, 'id': 622517715, 'password': '123123', 'guoqi': '2020-5-21', 'zonge': 15000}
622517715
总结:
1.序列化:内存---》字符串的转换
2.反序列化:字符串---》内存
6.2通过pickle的方式写入(不需要转换为字符串):(序列化pickle.dumps)
import pickle
account = {
"id": 622517715,
"zonge": 15000,
"yue": 8000,
"guoqi": "2020-5-21",
"password": "123123"
}
f = open("account.db", "wb") # pickle 默认依照bytes 格式存储所以 写入要已“wb” 格式
# print(pickle.dumps(account))
f.write(pickle.dumps(account)) # 等同于 pickle.dump(account, f) 将account 写入到 f 文件中
f.close()
6.3在另一个文件中加载序列化文件:(反序列化pickle.loads)
import pickle
f = open("account.db", "rb") # pickle 默认依照bytes 格式存储所以 读取要已“rb” 格式
account = pickle.loads(f.read()) # 等同于 account = pickle.load(f) 自动帮助read()
print(account)
print(account["id"])
输出:
{'password': '123123', 'id': 622517715, 'yue': 8000, 'guoqi': '2020-5-21', 'zonge': 15000}
622517715
6.4反序列化后,修改值在存入到文件中(反序列化--》修改--》序列化)
import pickle
f = open("account.db", "rb")
account = pickle.loads(f.read()) # 等同于 account = pickle.load(f) 自动帮助read()
print(account)
print(account["id"])
account["yue"] -= 3000
f = open("account.db", "wb")
f.write(pickle.dumps(account)) # 等同于 pickle.dump(account, f) 将account 写入到 f 文件中
f.close()
print(account)
输出:
{'password': '123123', 'id': 622517715, 'yue': 8000, 'guoqi': '2020-5-21', 'zonge': 15000}
622517715
{'password': '123123', 'id': 622517715, 'yue': 5000, 'guoqi': '2020-5-21', 'zonge': 15000}
json模块
pickle 和 json的区别
1.json只支持 str,int,float,set,dict,list,tuple
2.json跨平台通用的序列化的格式
3.pickle 支持 Python中的所有格式;但是不能和其他平台语言通用;
4.pickle 存储格式为bytes,所以写入和读取的时候 需要依照("wb" "rb")形式打开
1.使用json实现序列化和反序列化,直接通过别名as
import json as pickle
account = {
"id": 622517715,
"zonge": 15000,
"yue": 8000,
"guoqi": "2020-5-21",
"password": "123123"
}
# f = open("account.db", "wb")
f = open("account.db", "w")
f.write(pickle.dumps(account)) # 等同于 pickle.dump(account, f)
f.close()
2.反序列化将存入的数据读取出来:
import json as pickle
# f = open("account.db", "rb")
f = open("account.db", "r")
account = pickle.load(f)
print(account)
print(account["id"], account["yue"])
f.close()
输出:
{'passwd': '123123', 'id': 376415700, 'balance': 8000, 'exp_date': '2019-5-20', 'credit': 15000}
376415700 8000
7.logging模块
很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug(), info(), warning(), error() and critical() 5个级别;
7.1 日志模块的使用(输出屏幕):
import logging
logging.warning("user [bao] password more than 3 times")
logging.critical("server is down")
输出:
WARNING:root:user [bao] password more than 3 times
CRITICAL:root:server is down
7.2 将日志写到文件中(basicConfig方法):
import logging
#语法:logging.basicConfig(filename="日志名称", level=logging.级别达到级别就写入)
logging.basicConfig(filename="example.log", level=logging.INFO)
logging.debug('This message should go to the log file') # 由于是INFO 级别所以debug日志内容不会写入到 文件中
logging.warning("user [bao] password more than 3 times")
logging.critical("server is down")
logging.info('So should this')
example.log文件内容:
WARNING:root:user [bao] password more than 3 times
CRITICAL:root:server is down
INFO:root:So should this
7.3 将日志输出是加上时间:
import logging
logging.basicConfig(filename="example.log",
level=logging.DEBUG,
format='%(asctime)s %(message)s', # asctime 当前时间 message 日志内容
datefmt='%Y/%m/%d %H:%M:%S %p' # 日期格式
)
logging.debug('This message should go to the log file')
logging.warning("user [bao] password more than 3 times")
logging.critical("server is down")
logging.info('So should this')
example.log文件内容:
2017/02/23 18:34:07 PM This message should go to the log file
2017/02/23 18:34:07 PM user [bao] password more than 3 times
2017/02/23 18:34:07 PM server is down
2017/02/23 18:34:07 PM So should this
7.4 将日志按照需求的模块打印(asctime 当前时间 process 进程ID filename 文件的名字 funcName 函数的名字 lineno 打印的哪一行 message 日志内容)
import logging
logging.basicConfig(filename="example.log",
level=logging.DEBUG,
format='%(asctime)s pid:%(process)d %(filename)s:%(funcName)s:%(lineno)d %(message)s',
# asctime 当前时间 process 进程ID filename 文件的名字 funcName 函数的名字 lineno 打印的哪一行 message 日志内容
datefmt='%Y/%m/%d %H:%M:%S %p' # 日期格式
)
def sayhi():
logging.info('print logging in sayhi')
logging.debug('This message should go to the log file')
logging.warning("user [bao] password more than 3 times")
logging.critical("server is down")
logging.info('So should this')
sayhi()
example.log文件内容:
2017/02/23 18:54:36 PM pid:19552 loggings模块.py:<module>:17 This message should go to the log file
2017/02/23 18:54:36 PM pid:19552 loggings模块.py:<module>:18 user [bao] password more than 3 times
2017/02/23 18:54:36 PM pid:19552 loggings模块.py:<module>:19 server is down
2017/02/23 18:54:36 PM pid:19552 loggings模块.py:<module>:20 So should this
2017/02/23 18:54:36 PM pid:19552 loggings模块.py:sayhi:15 print logging in sayhi
7.5日志(按照:大小、时间)截断:
Python 使用logging模块记录日志涉及四个主要类:
- logger提供了应用程序可以直接使用的接口;
- handler将(logger创建的)日志记录发送到合适的目的输出(屏幕、文件);
- filter提供了细度设备来决定输出哪条日志记录(过滤筛选);
- formatter决定日志记录的最终输出格式。
调用关系(如图):
# 导入日志模块,导入日志切割模块
import logging
from logging import handlers
# 定义logger 接口
logger = logging.getLogger('TEST-LOG') # 向公共日志里打 文件时用于日志区分
logger.setLevel(logging.DEBUG) # 全局日志 级别(DEBUG)
# 屏幕handler 输出 ch
ch = logging.StreamHandler() # 屏幕 Handler 赋值给ch
ch.setLevel(logging.INFO) # 屏幕 输出日志级别(INFO)
# 文件handler 记录到文件中 日志 fh
# fh = logging.FileHandler("access.log") # 记录到access.log 文件中 赋值给 fh
fh = handlers.TimedRotatingFileHandler("access.log", when="h", interval=24, backupCount=7)
# 记录到文件中,每间隔24小时切割一份日志,一共保留7份超出的部分自动删除
# fh = handlers.RotatingFileHandler("access.log", maxBytes=4, backupCount=7) # 记录到文件中,当日志满4b后切割,保留7份
fh.setLevel(logging.INFO) # 记录到文件中 日志 级别(INFO)
# 写日志格式 时间---名字(TEST-LOG)---文本形式的日志级别---日志内容
formatter = logging.Formatter('%(asctime)s pid:%(process)d %(filename)s:%(funcName)s:%(lineno)d %(message)s')
# 将屏幕输出 handler 和 日志格式绑定起来 formatter ch
# 将文件输出 handler 和 日志格式绑定起来 formatter fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# 日志接口 也要和 屏幕输出 handler 绑定 ch
# 日志接口 也要和 文件输出 handler 绑定 fh
logger.addHandler(ch)
logger.addHandler(fh)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
logger.info('info message')
输出:
2017-02-24 11:30:41,039 pid:18580 loggings模块.py:<module>:64 info message
2017-02-24 11:30:41,039 pid:18580 loggings模块.py:<module>:65 warn message
2017-02-24 11:30:41,039 pid:18580 loggings模块.py:<module>:66 error message
2017-02-24 11:30:41,039 pid:18580 loggings模块.py:<module>:67 critical message
2017-02-24 11:30:41,039 pid:18580 loggings模块.py:<module>:68 info message
8.hashlib模块
hash:是一种算法,Python3.x里代替了md5模块和sha模块,主要提供SHA1,SHA224, SHA256, SHA384, SHA512 ,MD5 算法
8.1hash的特点
- 内容相同则hash运算结果相同,内容稍微改变则hash值则变
- 不可逆推
- 相同算法,无论效验多长的数据,得到的哈希值长度固定
- hash校验的数据类型需要时bytes类型
8.2语法
1 . 分批次传值,可以达到一样的效果
import hashlib
m=hashlib.md5()
m.update('hello'.encode('utf-8')) # 可以分批次传值
m.update('world'.encode('utf-8')) # 继续传值
print(m.hexdigest())
输出
fc5e038d38a57032085441e7fe7010b0
2 . 将值一次update过去,可以发现hash值是相同的
m=hashlib.md5()
m.update('helloworld'.encode('utf-8'))
print(m.hexdigest())
输出
fc5e038d38a57032085441e7fe7010b0
3 . 效验一个文本的内容是否完整
# 推荐使用一行行的效验
m = hashlib.md5()
with open("a.xml","rb") as f:
for line in f:
m.update(line)
print(m.hexdigest())
# 不推荐使用全部加载(耗资源)
m = hashlib.md5()
with open("a.xml","rb") as f:
m.update(f.read())
print(m.hexdigest())
输出:
41bbdc6e6eee194233645e72f83594cd
41bbdc6e6eee194233645e72f83594cd
4 . 除了md5模式的效验,还可以使用SHA1,SHA224, SHA256, SHA384, SHA512算法,使用方法相同
# 推荐使用一行行的效验
m = hashlib.sha512()
with open("a.xml","rb") as f:
for line in f:
m.update(line)
print(m.hexdigest())
# 不推荐使用全部加载(耗资源)
m = hashlib.sha512()
with open("a.xml","rb") as f:
m.update(f.read())
print(m.hexdigest())
输出:
bfd023774d6a7fafcf368afa8894e534e44995abeb6509c6988088e7a04af9dfb50caaf67e3259e9ad5bc53a36882798d0b3801e76f2a103f6ee609289a3774a
bfd023774d6a7fafcf368afa8894e534e44995abeb6509c6988088e7a04af9dfb50caaf67e3259e9ad5bc53a36882798d0b3801e76f2a103f6ee609289a3774a
8.3hmac模块(加盐)
hmac模块它内部对我们创建key和内容进行进一步的处理然后加密
#要想保证hmac最终结果一致,必须保证:
#1:hmac.new括号内指定的初始key一样
#2:无论update多少次,校验的内容累加到一起是一样的内容
import hmac
h1=hmac.new(b'lin') # 需要保证 hmac.new 的值为相同
h1.update(b'hello') # update值和md5形式一样,可以多次update
h1.update(b'world')
print(h1.hexdigest())
h2=hmac.new(b'lin') # 需要保证 hmac.new 的值为相同
h2.update(b'helloworld')
print(h2.hexdigest())
输出结果:
c10bd498bd6e7dbc5dd5c3fb3396a165
c10bd498bd6e7dbc5dd5c3fb3396a165
9.suprocess模块(可用于执行系统命令,将返回值输出到stdout、stderr)
1 . 用于执行系命令,默认将返回值直接输出到终端,可以指定输出到stdout、stderr
import subprocess
res = subprocess.Popen(r"dir C:UsersDpadPycharmProjectsPython 07", # 一条可执行的命令
shell=True, # 标准格式
stdout=subprocess.PIPE, # 将正确内容指向到stdout管道中
stderr=subprocess.PIPE,) # 将错误内容指向到stdout管道中
print("正确输出:", res.stdout.read().decode("gbk")) # 命令正确时,内容会放在stdout内部
print("错误输出:", res.stderr.read().decode("gbk")) # 命令执行错误时,内容会放在stderr内部
输出(发现错误输出内容为空):
正确输出: 驱动器 C 中的卷没有标签。
卷的序列号是 F2xA-37zC
C:UsersDpadPycharmProjectsPython 07 的目录
2017/08/15 00:35 <DIR> .
2017/08/15 00:35 <DIR> ..
2017/08/15 00:36 <DIR> hashblib模块
2017/08/15 00:53 <DIR> subprocess模块
2017/08/12 10:45 <DIR> xml模块
2017/08/12 18:11 <DIR> 面向对象
0 个文件 0 字节
6 个目录 168,254,607,360 可用字节
错误输出:
2 . 将得到的输出结果,通过stdin形式传入给另一个条件,实现管道查询
import subprocess
res1 = subprocess.Popen(r"dir C:UsersDpadVPN-FanX", # 查看该目录下的内容
shell=True,
stdout=subprocess.PIPE,) # 输出到stdout
res2 = subprocess.Popen(r"findstr exe$", # findstr查找依照 exe结尾的文件
shell=True,
stdin=res1.stdout, # 输入来源res1.stdout
stdout=subprocess.PIPE,) # 结果输出到stdout
print("依照exe结尾的文件有:
",res2.stdout.read().decode("gbk")) # 打印查找到的结果
输出:
依照exe结尾的文件有:
2015/08/04 01:41 305,664 Shadowsocks.exe
2013/05/27 10:46 2,617,344 ssocks32.exe
2013/05/27 10:46 3,225,600 ssocks64.exe
2013/06/05 12:55 952,320 yingwa.exe