008-Python-模块

时间:2022-05-03 14:53:14

1.模块

1.1什么是模块

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

模块分为:

  1. 内置模块(内部定义的如time,os,sys等)
  2. 第三方模块(需要安装)
  3. 自定义模块(自己定义的)

1.2为什么要使用模块

如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。

随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用,

2.模块的使用

2.1导入一个模块

  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

常用内置标准模块

  1. time 时间模块
  2. timedate 时间模块
  3. random,string模块(生成随机字符串)
  4. os模块
  5. sys模块
  6. json & pickle 模块
  7. 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

如图:

008-Python-模块

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
'\n'

4.13.1输出当前平台的换行符“windows”

>>> os.linesep
'\r\n'

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:\Users\Dpad\PycharmProjects\py_s16\day5\OS模块\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:\Users\Dpad\PycharmProjects\py_s16\day5\OS模块
C:\Users\Dpad\PycharmProjects\py_s16\day5

4.20返回path最后的文件名,如果path以/或\结尾,那么返回空

print(os.path.dirname(file_path))
print(os.path.basename(os.path.dirname(file_path))) 输出:
C:\Users\Dpad\PycharmProjects\py_s16\day5\OS模块
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\b

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:\Users\Dpad\PycharmProjects\PyS18\day05\a")

输出:

C:\Users\Dpad\PycharmProjects\PyS18\day05\a\a1.txt
C:\Users\Dpad\PycharmProjects\PyS18\day05\a\a2.txt
C:\Users\Dpad\PycharmProjects\PyS18\day05\a\b1\b1.txt
C:\Users\Dpad\PycharmProjects\PyS18\day05\a\b1\c1\c1.txt
C:\Users\Dpad\PycharmProjects\PyS18\day05\a\b2\b2.txt

4.29获取一个文件 a.mp4 的大小

C:\Users\Dpad\PycharmProjects\PyS18\000作业\002-FtpServer>dir
驱动器 C 中的卷没有标签。
卷的序列号是 F2CA-37BC C:\Users\Dpad\PycharmProjects\PyS18\000作业\002-FtpServer 的目录
2017/08/25 00:17 <DIR> .
2017/08/25 00:17 <DIR> ..
2017/08/19 17:59 88,960,348 a.mp4 C:\Users\Dpad\PycharmProjects\PyS18\000作业\002-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:\Users\admin>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模块记录日志涉及四个主要类:

  1. logger提供了应用程序可以直接使用的接口;
  2. handler将(logger创建的)日志记录发送到合适的目的输出(屏幕、文件);
  3. filter提供了细度设备来决定输出哪条日志记录(过滤筛选);
  4. formatter决定日志记录的最终输出格式。

    调用关系(如图):

    008-Python-模块
# 导入日志模块,导入日志切割模块
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的特点

  1. 内容相同则hash运算结果相同,内容稍微改变则hash值则变
  2. 不可逆推
  3. 相同算法,无论效验多长的数据,得到的哈希值长度固定
  4. 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:\Users\Dpad\PycharmProjects\Python\007",     # 一条可执行的命令
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:\Users\Dpad\PycharmProjects\Python\007 的目录 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:\Users\Dpad\VPN-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结尾的文件有:\n",res2.stdout.read().decode("gbk")) # 打印查找到的结果

输出:

依照exe结尾的文件有:
2015/08/04 01:41 305,664 *.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