python笔记7 logging模块 hashlib模块 异常处理 datetime模块 shutil模块 xml模块(了解)

时间:2023-03-09 01:15:27
python笔记7 logging模块   hashlib模块   异常处理   datetime模块  shutil模块 xml模块(了解)

logging模块

日志就是记录一些信息,方便查询或者辅助开发

记录文件,显示屏幕

低配日志, 只能写入文件或者屏幕输出

屏幕输出

import logging

logging.debug('调试模式')     #默认只输出warning以上信息,
logging.info('正常运行')
logging.warning('警告')
logging.error('错误')
logging.critical('系统崩溃') WARNING:root:警告
ERROR:root:错误
CRITICAL:root:系统崩溃

写入文件

import logging
logging.basicConfig(
level=logging.DEBUG,
#level=, # 显示的级别
format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', # 显示格式
datefmt='%Y %m %d', # 日期
filename='a.log', # 默认是a模式, 就是使用的gbk 编码。
# filemode='w' #一般只用追加写入,不用写入 因此不用改写模式。
) logging.debug('调试模式') # 等于10
logging.info('正常运行')      # 等于20
logging.warning('警告')      # 等于30
logging.error('错误')        # 等于40
logging.critical('系统崩溃')    # 等于50

标配日志,可屏幕输出也可记录日志

import logging

# 创建logging对象
log = logging.getLogger() # 创建文件对象
f1 = logging.FileHandler('file1.log', encoding='utf-8')
f2 = logging.FileHandler('file2.log', encoding='utf-8') #创建屏幕对象
sh = logging.StreamHandler() # 日志格式设置
format1 = logging.Formatter(
fmt='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', # 显示格式
datefmt='%Y-%m-%d %H:%M:%S',) #显示时间设置
format2 = logging.Formatter(
fmt='%(asctime)s %(filename)s %(levelname)s ', # 显示格式
datefmt='%Y-%m-%d %H:%M:%S',) #显示时间设置
format3 = logging.Formatter(
fmt='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', # 显示格式
datefmt='%Y-%m-%d %H:%M:%S',) #显示时间设置
# 给创建的输出对象绑定格式
f1.setFormatter(format1)
f2.setFormatter(format2)
sh.setFormatter(format3) #给log对象添加输出对象
log.addHandler(f1)
log.addHandler(f2)
log.addHandler(sh) #设置级别
log.setLevel()
sh.setLevel()
f1.setLevel()
f2.setLevel() logging.debug('调试模式')
logging.info('正常运行')
logging.warning('警告')
logging.error('错误')
logging.critical('系统崩溃')

高配日志

通过导入文件(字典的方式)写日志,Django

import os
import logging.config # 定义日志的输出的格式
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 找到当前目录绝对路径 __file__
logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录的绝对路径
logfile_name = '高配版.log' # log文件名
# # 如果不存在定义的日志目录就创建一个
# if not os.path.isdir(logfile_dir):
# os.mkdir(logfile_dir)
# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)
# log配置字典
# 第一层键值对的键固定的关键字不能改变。
LOGGING_DIC = {
'version': 1, # 版本
'disable_existing-loggers': False, # 禁用现有的log日志
'formatters': { # 定义三种不同的日志格式
'standard': { # 格式1
'format': standard_format
},
'simple': { # 格式2
'format': simple_format
},
'id_simple_format': { # 格式3
'format': id_simple_format
}
},
'filters': {}, # 过滤
'handlers': {
'console': { # 打印到终端的日志
'level': 'DEBUG', # 日志级别
'class': 'logging.StreamHandler', # 类:打印到屏幕
'formatter': 'simple' # 日志的格式
},
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard', # 日志的格式
'filename': logfile_path, # 日志文件的绝对路径
'maxBytes': 1024*1024*5, # 日志大小5M,以bytes
'backupCount': 5, # 最多只有5个文件
'encoding': 'utf-8',
},
},
'loggers': {
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
},
}
logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
# # logging.config # 将你写好的logging 字典 在导入logging.config后,传到logging模块中
logger = logging.getLogger() # 生成一个log实例 通过字典自己设置的个性化的log对象 logger.info('正常运行状态') # 记录该文件的运行状态

hashlib模块

1.加密的类型必须是str

2.无论这个str多长,加密之后都是转化成等长度的数字.

3.无论在任何机器上,

不同的字符串加密后一定不同

import hashlib

ret = hashlib.md5()    #定义一个ret的对象
ret.update('wk'.encode('utf-8')) #将字符串'wk'转为bytes 加密
print(ret.hexdigest()) #查看转换后的密文 5d2bf8e6622cb88ca16a745dcf8153a0

用途:

1,对密码进行加密

md5加密

a.普通的md5加密

import hashlib

def encryption(passwd):                #加密函数
ret = hashlib.md5()
ret.update(passwd.encode('utf-8'))
return ret.hexdigest() def register():
user = input('>>>')
passwd = input('>>>')
passwd = encryption(passwd)
with open('ku', encoding='utf-8', mode='a') as f1:
f1.write('{}|{}'.format(user, passwd)) register()

用户注册完登录时,将登陆的密码再次加密然后与存储的进行对比

b,加盐

import hashlib

def encryption(passwd):
ret = hashlib.md5('加盐'.encode('utf-8')) #在别人设置的密码前再加一串固定的字符,使md5不容易破译,但是如果别人知道你的盐是什么还是可以破译
ret.update(passwd.encode('utf-8'))
return ret.hexdigest() def register():
user = input('>>>')
passwd = input('>>>')
passwd = encryption(passwd)
with open('ku', encoding='utf-8', mode='a') as f1:
f1.write('{}|{}'.format(user, passwd)) register()

c.动态加盐

import hashlib

def encryption(user, passwd):
ret = hashlib.md5(user[::2].encode('utf-8')) #加的盐为用户名字符的奇数字符
ret.update(passwd.encode('utf-8'))
return ret.hexdigest() def register():
user = input('>>>')
passwd = input('>>>')
passwd = encryption(user,passwd)
with open('ku', encoding='utf-8', mode='a') as f1:
f1.write('{}|{}'.format(user, passwd)) register()

sha加密

import hashlib

def encryption(user, passwd):
ret = hashlib.sha1(user[::2].encode('utf-8')) #与md5用法一样,把md5改为sha1
ret.update(passwd.encode('utf-8'))
return ret.hexdigest() def register():
user = input('>>>')
passwd = input('>>>')
passwd = encryption(user,passwd)
with open('ku', encoding='utf-8', mode='a') as f1:
f1.write('{}|{}'.format(user, passwd)) register()

python笔记7 logging模块   hashlib模块   异常处理   datetime模块  shutil模块 xml模块(了解)

哈希的加密方法有很多,尾数越高,加密方法越复杂,效率越低

2.文件的校验

校验文件就是把文件的内容生成MD5值,把MD5值对比校验

校验文件

import hashlib
def file_hashlib(file):
ret = hashlib.md5()
with open(file,mode='rb') as f1:
ret.update(f1)
return ret.hexdigest()
file_hashlib('文件')

校验可以累加

import hashlib
s1 = '蹦沙卡拉卡' #一个字符串一次性读取和分次读取其生成的MD5值一样(必须是相同字符串)
ret = hashlib.md5()
ret.update(s1.encode('utf-8'))
print(ret.hexdigest()) ret = hashlib.md5()
ret.update('蹦'.encode('utf-8'))
ret.update('沙'.encode('utf-8'))
ret.update('卡'.encode('utf-8'))
ret.update('拉'.encode('utf-8'))
ret.update('卡'.encode('utf-8'))
print(ret.hexdigest()) 5f46742e84df43713d132852859aa3bb
5f46742e84df43713d132852859aa3bb

对于大文件每次读取一行,按行累加校验

import hashlib
def file_hashlib(file):
ret = hashlib.md5()
with open(file,mode='rb') as f1:
for i in f1:        # 循环每行读取
ret.update(i)
return ret.hexdigest()
file_hashlib('文件')

异常处理

异常发生后下边的代码就不再执行了

单支情况  try except

name                      #单有一个变量名运行

Traceback (most recent call last):                #报错
File "F:/python24期/python/123.py", line 1, in <module>
name
NameError: name 'name' is not defined #报错 NameError

try--except: 尝试着运行try里面的代码,出现错误,按照错误类型去寻找相应的except,找到执行except里的代码,然后程序继续运转.

try:                    #代码可以运行并且不报错
print(555)
name #出现错误即跳转到except,不在往下执行
print(666)
except NameError:            #定义错误类型
print('name name is not defined')
print(777) 555 #错输出结果可见,try里的 错误代码下的代码不执行, 遇到错误后看except是否有指定错误,如果有,执行except里的代码,
name name is not defined
777

上述方法只能锁定一个错误,如果错误没有在except里,则程序还会报错

try:
print(555)
l1 = [1, 2, 3]
print(l1[10]) #打印列表的第10个参数,但是列表里只有2个参数 此时报IndexError错误
print(666)
except NameError: #except里没有定义IndexError错误,因此程序执行到print(l1[10])还是会报错并终止程序
print('name name is not defined')
print(777) Traceback (most recent call last):
555
File "F:/python24期/python/123.py", line 4, in <module>
print(l1[10])
IndexError: list index out of range

多支情况 try except except except ......

try:
print(555)
name
l1 = [1, 2, 3]
print(l1[10])
print(666)
dic = {'name': 'alex'}
print(dic['age'])
except NameError: #定义多个except,但是还是try里的代码,遇到错误即停止往下执行
print('name name is not defined')
except IndexError:
print('索引超出范围....')
except KeyError:
print('没有此key...')
print(777) 555
name name is not defined
777

万能处理  Exception

如果你对错误原因不关心,只是想不让其报错,那么程序中你就用万能处理.

如果你对错误原因需要进行不同分流或者程序处理,那么就需要多分支.

try:
print(555)
name
l1 = [1, 2, 3]
print(l1[10])
print(666)
dic = {'name': 'alex'}
print(dic['age'])
except Exception as e: #Exception可以接收所有错误, as e 把错误结果赋值给e
print(e)
print(777) 555
name 'name' is not defined
777

多分支加万能处理

try:
print(555)
name
l1 = [1, 2, 3]
print(l1[10])
print(666)
dic = {'name': 'alex'}
print(dic['age'])
except NameError: #定义多个except,
print('name name is not defined')
except IndexError:
print('索引超出范围....')
except KeyError:
print('没有此key...')
except Exception as e: #前边分流接收,最后以Exception 收尾
print(e)
print(777)

try  except  else

try:
print(555)
name
except NameError:
print('name name is not defined')
else:   #如果try里报错并且执行except,则代码往下走不执行else
print(999)
print(777) 555                  #输出结果没有执行else里的代码
name name is not defined
777 try:
print(555)
name = 123
except NameError: #如果try里的代码没有报错,并且没有执行except,则执行else里的代码
print('name name is not defined')
else:
print(999)
print(777) 555
999                    #此处执行了else里的代码
777

try  finally

finaly 不管对与错都执行finally 但是代码不会继续往下走,

try:
name = 123
finally:
print()
try:
li = [1,2,3]
print(li[10])
finally:
print()
print(888) #print(888)没有执行 Traceback (most recent call last):
777                #不管对错finally内的代码都执行了 File "F:/python24期/python/123.py", line 7, in <module>
print(li[10])
IndexError: list index out of range

常作用于关闭文件,关闭连接,关闭数据库等等

f1 = open('a.log', encoding='utf-8')
f1.read()
'''
各种对文件操作的代码,但是可能会出错,出错之后,你的文件句柄无法关闭。
'''
f1.close() # 解决方案:
try:
f1 = open('a.log', encoding='gbk')
f1.read()
f1.write('sfdsf')
'''
各种对文件操作的代码,但是可能会出错,出错之后,你的文件句柄无法关闭。
'''
finally:
print(666)
f1.close()

try  findally也可以作用于函数

def aa(x):
try:
c = x + 1
return c
finally: #finally作用于函数先执行finally再执行return
print(666)
print(aa(1)) 666          #先执行的findlly
2            #再执行的c=2

try except finally

try:
name = 123
finally:
print(777)
try:
li = [1,2,3]
print(li[10])
except Exception:
pass
finally:
print(666)
print(888) 777
666
888

自定义异常处理

python提供了大部分异常,但是不是所有,比如 大的框架的手机连接问题,网络引发的代码问题等等.

Exception 也处理不了.

class PhoneConnectionError(BaseException):      #定义一个类,继承BaseException 类
pass
raise PhoneConnectionError('错误类型') #raise报一个指定的错误,此错误必须定义class PhoneConnectionError(BaseException):才能出现 Traceback (most recent call last):
File "F:/python24期/python/123.py", line 5, in <module>
raise PhoneConnectionError('错误类型')
__main__.PhoneConnectionError: 错误类型       #PhoneConnectionError的错误

要想让except能够找到自定义的错误类型,需要自定义一个错误类并且继承BaseException累

class PhoneConnectionError(BaseException):               #如果出现python解决不了的错误类型,就定义一个错误类,让这个类继承BaseException
pass
try:
raise PhoneConnectionError('错误类型')
except PhoneConnectionError:
print('手机连接出现了问题') 手机连接出现了问题

assert  断言  只要条件不成立就报错

assert 1 == 2              #源码中经常遇到 只要条件不成立,我就抛出错误

Traceback (most recent call last):
File "F:/python24期/python/123.py", line 1, in <module>
assert 1 == 2
AssertionError

datetime模块

获取当前时间

import datetime
now_time = datetime.datetime.now()
print(now_time) 2019-01-10 19:49:42.388032

获取3周之后和3周之前的当前时间

import datetime
print(datetime.datetime.now())
print(datetime.datetime.now()+datetime.timedelta(weeks=3)) #3周之后的时间
print(datetime.datetime.now()+datetime.timedelta(weeks=-3)) #3周之前的时间 2019-01-10 19:55:01.222595
2019-01-31 19:55:01.222595
2018-12-20 19:55:01.222595

获取其他时间

import datetime
print(datetime.datetime.now())
print(datetime.datetime.now()+datetime.timedelta(days=3)) #3天后
print(datetime.datetime.now()+datetime.timedelta(days=-3)) #3天前
print(datetime.datetime.now()+datetime.timedelta(hours=3)) #3小时后
print(datetime.datetime.now()+datetime.timedelta(hours=-3)) #3小时前
print(datetime.datetime.now()+datetime.timedelta(minutes=3)) #3分钟后
print(datetime.datetime.now()+datetime.timedelta(minutes=-3)) #3分钟前
print(datetime.datetime.now()+datetime.timedelta(seconds=3)) #3秒后
print(datetime.datetime.now()+datetime.timedelta(seconds=-3)) #3秒前 2019-01-10 19:59:35.137924
2019-01-13 19:59:35.137924
2019-01-07 19:59:35.137924
2019-01-10 22:59:35.137924
2019-01-10 16:59:35.137924
2019-01-10 20:02:35.137924
2019-01-10 19:56:35.137924
2019-01-10 19:59:38.137924
2019-01-10 19:59:32.137924

可直接调整到年月日时分秒

import datetime
current_time = datetime.datetime.now()
print(current_time.replace(year=1977)) # 直接调整到1977年
print(current_time.replace(month=1)) # 直接调整到1月份
print(current_time.replace(year=1989,month=4,day=25)) # 1989-04-25 18:49:05.898601 1977-01-10 20:03:57.756185
2019-01-10 20:03:57.756185
1989-04-25 20:03:57.756185

将时间戳转化成时间

import datetime
print(datetime.date.fromtimestamp(1232132131)) 2009-01-17

shutil模块

对普通文件操作

高级的 文件、文件夹、压缩包 处理模块

shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中

import shutil

shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

shutil.copyfile(src, dst)
拷贝文件

shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在

shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变

shutil.copymode('f1.log', 'f2.log') #目标文件必须存在

shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copystat('f1.log', 'f2.log') #目标文件必须存在

shutil.copy(src, dst)
拷贝文件和权限

import shutil

shutil.copy('f1.log', 'f2.log')

shutil.copy2(src, dst)
拷贝文件和状态信息

import shutil
shutil.copy2('f1.log', 'f2.log')

shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹

import shutil

shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 

shutil.rmtree(path[, ignore_errors[, onerror]])递归的去删除文件

import shutil

shutil.rmtree('folder1')

shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。

shutil.move('folder1', 'folder3')

打包压缩

shutil.make_archive(base_name, format,...)

创建压缩包并返回文件路径,例如:zip、tar

创建压缩包并返回文件路径,例如:zip、tar

      • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
        如 data_bak                       =>保存至当前路径
        如:/tmp/data_bak =>保存至/tmp/
      • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
      • root_dir: 要压缩的文件夹路径(默认当前目录)
      • owner: 用户,默认当前用户
      • group: 组,默认当前组
      • logger: 用于记录日志,通常是logging.Logger对象
#将 /data 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data') #将 /data下的文件打包放置 /tmp/目录
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close() # 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close() zipfile压缩解压缩 import tarfile # 压缩
>>> t=tarfile.open('/tmp/egon.tar','w')
>>> t.add('/test1/a.py',arcname='a.bak')
>>> t.add('/test1/b.py',arcname='b.bak')
>>> t.close() # 解压
>>> t=tarfile.open('/tmp/egon.tar','r')
>>> t.extractall('/egon')
>>> t.close() tarfile压缩解压缩

xml模块(了解)

xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,
大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
现在这种格式的文件比较少了,但是还是存在的所以大家简单了解一下,以备不时之需。

xml文件

<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data> xml数据 xml文件
# 增删改查
# 在进行操作之前,都应该进行这两步: # import xml.etree.ElementTree as ET
# tree = ET.parse('a.xml') # 形成树形结构
# root = tree.getroot() # 得到树的根系
# print(root)
# 循环打印:
# for i in root:
# print(i)
# <Element 'country' at 0x00000196B51191D8>
# <Element 'country' at 0x00000196B5124B88>
# <Element 'country' at 0x00000196B5124D18> # 所有的增删改查都是基于这个root根系去操作 # 查:
# 1,全文搜索 year 将所有的year标签全部找
# print(root.iter('year'))
# print([i for i in root.iter('year')])
# 2,只找第一个,找到就返回
# print(root.find('country'))
# 3,在root的子节点找,找所有的
# print(root.findall('country')) # 练习
# 找到标签也可以找到标签相应的内容:tag,attrib,text # 1,找所有的rank标签,以及 attrib 和 text (这里利用列表推导式比较方便)
# print([i for i in root.iter('rank')])
# [<Element 'rank' at 0x000001367D0D49F8>, <Element 'rank' at 0x000001367D0D4BD8>, <Element 'rank' at 0x000001367D0D4D68>]
# print([i.attrib for i in root.iter('rank')])
# [{'updated': 'yes'}, {'updated': 'yes'}, {'updated': 'yes'}]
# print([i.text for i in root.iter('rank')]) # ['2', '5', '69'] # 2,找到第二个country的 neighbor标签以及他的属性
# print([tag for tag in root.findall('country')][1].find('neighbor').attrib)
# {'direction': 'N', 'name': 'Malaysia'} # 增 append
# import xml.etree.ElementTree as ET
# tree = ET.parse('a.xml') # 形成树形结构
# root = tree.getroot() # 得到树的根系 # 给 year 大于2010年的所有标签下面添加一个month标签,属性为name:month 内容为30days # for country in root.findall('country'):
# for year in country.findall('year'):
# if int(year.text) > 2010:
# month = ET.Element('month')
# month.text = '30days'
# month.attrib = {'name': 'month'}
# country.append(month)
# tree.write('b.xml') #改 # import xml.etree.ElementTree as ET
# tree = ET.parse('a.xml') # 形成树形结构
# root = tree.getroot() # 得到树的根系
# 对所有的year属性以及值进行修改
# for node in root.iter('year'):
# new_year=int(node.text)+1
# node.text=str(new_year)
# node.set('updated','yes')
# node.set('version','1.0')
# tree.write('test.xml') # 删
# import xml.etree.ElementTree as ET
# tree = ET.parse('a.xml') # 形成树形结构
# root = tree.getroot() # 得到树的根系
#
# # 将 rank值大于50的country标签删除
# for country in root.findall('country'):
# rank = int(country.find('rank').text)
# if rank > 50:
# root.remove(country)
#
# tree.write('output.xml') 对xml的增删改查简单操作
import xml.etree.ElementTree as ET

new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = ''
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '' et = ET.ElementTree(new_xml) #生成文档对象
et.write("test.xml", encoding="utf-8",xml_declaration=True) ET.dump(new_xml) #打印生成的格式 自己创建xml文档