包,logging模块,hashlib模块(摘要算法模块),openpyxl(操作excel表格模块),深浅拷贝(copy模块)
包,logging模块,hashlib模块(摘要算法模块),openpyxl(操作excel表格模块),深浅拷贝(copy模块)
包:
模块的四种表示形式:
- 1.py文件(重要)
- 2.共享库
- 3.包:文件夹(一系列模块的结合体)(重要)
- 4.C++编译的连接到python内置的
研究模块与包,还可以站在另外两个角度分析不同的问题
- 1.模块的开发者
- 2.模块的使用者
导入模块时会瞬间发生的操作:
- 先产生一个执行文件的名称空间
- 1.创建模块文件的名称空间
- 2.执行模块文件中的代码,将产生的名字放入模块的名称空间中
- 3.在执行文件中拿到一个指向模块名称空间中的名字
什么是包?
- 它是一系列模块文件夹的结合体,表现形式就是一个文件夹
- 该文件夹内部通常会有一个__init__.py文件
- 包的本质还是一个模块
首次导入包:
- 1.创建包下面的__init__.py文件的名称空间
- 2.执行包下面的__init__.py文件中的代码,将产生的名字放入包下面的__init__.py文件的名称空间中
- 3.在执行文件中拿到一个指向包下面的__init__.py文件名称空间中的名字
注意点:在导入语句中, . 号的左边肯定是一个包(文件夹),比如from p.dir.m import f() 中p就是一个包文件名
设计包时:
- 1.当模块的功能特别多时,应该分文件管理
- 2.每个模块之间为了避免后期模块改名的问题,你可以使用相对导入(包里面的文件都应该是被导入的模块)
站的包的开发者:
- 如果使用绝对路径来管理自己的模块,那么永远只需要以包的路径为基准依次导入模块
站在包的使用者:
- 你必须得将包所在的那个文件夹路径添加到system path中
知识点补充(面试可能会遇到):
- python2如果要导入包,包下面必须要有双下init.py文件
- python3如果要导入包,包下面没有双下init.py也不会报错
- 当你在删程序不必要的文件时,千万不要随意删除双下init.py文件
logging模块:
日志模块:主要的作用就是记录
import logging # 非终端显示日志: logging.basicConfig(filename='access.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=10) # 其中用stream=True可以让日志打印到终端,不过stream不能与filename一同使用 # 日志分为5个等级,重要度由上至下依次增加 logging.debug('debug日志') # 10调试 logging.info('info日志') # 20用户操作记录 logging.warning('warning日志') # 30警告 logging.error('error日志') # 40程序报错提示 logging.critical('critical日志') # 50程序逻辑出错类
关于日志需要解决的问题:
- 1.乱码
- 2.日志格式
- 3.如何既打印到终端又写到文件中
关于日志中的一些对象:
- 1.logger对象:负责产生日志
- 2.filter对象:负责过滤日志(了解即可)
- 3.handler对象:负责控制日志输出的位置(文件/终端)
- 4.formmater对象:规定日志内容的格式
生成日志等常规操作(方法),一共8个步骤:
import logging # 1.logger对象:负责产生日志 logger = logging.getLogger('转账记录') # 2.filter对象:负责过滤日志(了解即可) # 3.handler对象:负责控制日志输出的位置(文件/终端) hd1 = logging.FileHandler('a1.log',encoding='utf-8') # 输出到文件中 hd2 = logging.FileHandler('a2.log',encoding='utf-8') # 输出到文件中 hd3 = logging.StreamHandler() # 输出到终端中 # 4.formmater对象:规定日志内容的格式 fm1 = logging.Formatter( fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', ) fm2 = logging.Formatter( fmt='%(asctime)s - %(name)s - %(message)s', datefmt='%Y-%m-%d, ) # 5.给logger对象绑定handler对象 logger.addHandler(hd1) logger.addHandler(hd2) logger.addHandler(hd3) # 6.给handler对象绑定formmate对象 hd1.setFormatter(fm1) hd2.setFormatter(fm2) hd3.setFormatter(fm3) # 7.设置日志等级 logger.setlevel(10) # 8.记录日志 logger.debug('写了半天,好累啊,好热啊,好像放空自我')
logging配置字典:
log配置字典:
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' # 定义日志输出格式 结束(其中,logfile_dir与logfile_name变量值需要手动修改) logfile_dir = os.path.dirname(os.path.dirname(__file__)) # log文件的目录,需要寻上上一级的目录 logfile_dir = os.path.dirname(__file__) # log文件的目录,只需要寻上一级的目录 logfile_name = 'a3.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, 'formatters':{ 'standard':{ 'format':standard_format }, 'simple':{ 'format':simple_format }, }, 'fileters':{}, # 过滤日志 'handlers':{ # 打印到终端的日志 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', # 打印到屏幕 'formatter':'simple' }, # 打印到文件的日志,收集info及以上的日志 'default':{ 'level':'DEBUG', 'class':'logging.handlers.RotaingFileHandler', # 保存到文件 'formatter':'standard', 'filename':logfile_path # 日志文件 'maxBytes': 1024*1024*5 # 日志大小 5M 'backupCount':5, # 最多可以新建5个,超过5个则全部清除再重新新建,直至再次达到5个 'encoding':'utf-8', # 日志文件的编码,解决中文乱码问题 }, }, 'loggers':{ # logging.getLogger(__name__)拿到的logger配置 ' ':{ 'handlers':['default','console'], # 这里将上面定义的两个handler都加上了,即log数据既写入文件又写入终端 'level':'DEBUG', 'propagate':True, # 向上(更高level的logger)传递 }, # 当键不存在的情况下,默认都会使用该key:value配置 }, } # 使用日志字典配置 logger = logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置 logger1 = logging.getLogger(' ') logger1.debug('好好的,不要浮躁,努力就有回报') # 括号内日志内容为手动输入
只需要我们记住的三段代码(重要):
# 使用日志字典配置 logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中配置 logger1 = logging.getLogger(' ') logger1.debug('好好的 不要浮躁 努力就有收获') # 括号内日志内容为手动输入
补充知识点:
- 当键不存在的情况下,默认使用 ' ':{ } 配置
logging在项目中的使用:ATM
start.py:
import os import sys BASE_DIR = os.path.dirname(__file__) sys.path.append(BASE_DIR) from core import src if __name__ == '__main__': src.run()
src.py:
form conf import settings from lib import common def register(): logger = common.get_logger('用户注册') username = input('输入用户名:').strip() password = input('输入密码:').strip() logger.info('%s注册了我们的网站'%username) func_dic = { '1':register } def run(): while True: print(''' 1 注册 ''') choice = input('请输入选择:').strip() if choice not in func_dic:continue func_dic.get(choice)()
settings.py:
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' # 定义日志输出格式 结束 BASE_DIR = os.path.dirname(os.path.dirname(__file__)) logfile_dir = os.path.join(BASE_DIR,'log') # log文件的目录,只需要寻上一级的目录 logfile_name = 'a3.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, 'formatters':{ 'standard':{ 'format':standard_format }, 'simple':{ 'format':simple_format }, }, 'fileters':{}, # 过滤日志 'handlers':{ # 打印到终端的日志 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', # 打印到屏幕 'formatter':'simple' }, # 打印到文件的日志,收集info及以上的日志 'default':{ 'level':'DEBUG', 'class':'logging.handlers.RotaingFileHandler', # 保存到文件 'formatter':'standard', 'filename':logfile_path # 日志文件 'maxBytes': 1024*1024*5 # 日志大小 5M 'backupCount':5, # 最多可以新建5个,超过5个则全部清除再重新新建,直至再次达到5个 'encoding':'utf-8', # 日志文件的编码,解决中文乱码问题 }, }, 'loggers':{ # logging.getLogger(__name__)拿到的logger配置 ' ':{ 'handlers':['default','console'], # 这里将上面定义的两个handler都加上了,即log数据既写入文件又写入终端 'level':'DEBUG', 'propagate':True, # 向上(更高level的logger)传递 }, # 当键不存在的情况下,默认都会使用该key:value配置 }, } if __name__ == '__main__' : # 使用日志字典配置 logger = logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置 logger1 = logging.getLogger(' ') logger1.debug('好好的,不要浮躁,努力就有回报')
common.py:
import logging.config from conf import settings def get_logger(name): logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中配置 logger1 = logging.getLogger(name) return logger1
hashlib模块:
定义:它是一个帮我们加密的模块
import hashlib # 这种加密过程是无法解密的 md = hashlib.md5() # 生成一个帮你造密文的对象 md.update('hello'.encode('utf-8')) # 往对象里面传入明文数据,且update只能接收bytes数据 md.update(b'hello') # 这样也行 print(md.hexdigest()) # 获取明文数据对应的秘文
知识点补充: 撞库操作(脱裤,洗库)
不同的算法,使用方法是相同的:
- 密文的长度越长,内部对应的算法越复杂;
但是:
- 1.时间消耗越长
- 2.占用空间更大
注意点:通常情况下使用md5算法,就足够了
import hashlib # 只要传入的内容相同,那么生成的密文肯定相同 md = hashlib.md5() md.update(b'areyouok?'') print(md.hexdigest()) # 密文1 md = hashlib.md5() md.update(b'are') md.update(b'you') md.update(b'ok?') print(md.hexdigest()) # 密文2与密文1一致
hashlib模块应用场景:
- 1.密码的密文存储
- 2.校验文件内容是否一致(通过比对md.hexdigest()返回出的二进制码)
- 3.快速上传文件,也可以通过比对密文二进制码
加盐处理:
import hashlib md = hashlib.md5() # 公司本身 在每一个需要加密的数据之前,先手动添加一些内容 md.update('你自己自定义的内容') md.update(b'hello') print(md.hexdigest())
动态加盐:
import hashlib def get_md5(data): md = hashlib.md5() md.update('加盐') md.update(data.encode('utf-8')) return md.hexdigest() password = input('>>>:') res = get_md5(password) print(res)
openpyxl模块:
它近几年比较火的操作excel表格的模块
写操作:
from openpyxl import Workbook wb = Workbook() # 先 生成一个工作簿 wb1 = wb.create_sheet('index',0) #创建一个表单页,还可以通过数字控制位置 wb2 = wb.create_sheet('index1') wb1.title = 'login' # 可以通过wb.title来改变表单页的名字 wb1['A3'] = 666 wb1['A4'] = 666 wb1.cell(rew=6,column=3,value=88888) #第六行第三列输入一个88888的值 wb1['A5'] = '=sum(A3:A4)' # 求和函数 # 创建表格文件 wb1.append(['username','age','hobby']) wb1.append(['jason',18,'study']) wb1.append(['tank',36,'吃生蚝']) wb1.append(['egon',44,'女教练']) wb1.append(['sean',22,'会所']) wb1.append(['nick',28,]) wb1.append(['ZZJ','','文娱委员']) wb.save('test.xlsx') # 保存新建的excel文件
读文件操作:
from openpyxl import load_workbook # 相当于 读文件 wb = load_workbook('test.xlsx',read_only=True) print(wb.sheetnames) # ['login','Sheet','index1'] print(wb['login']['A3'].value) # 666 print(wb['login']['A4'].value) # 444 print(wb['login']['A5'].value) # sum(A3:A4) wb = load_workbook('test.xlsx',read_only=True,data_only=True) print(wb.sheetnames) # ['login','Sheet','index1'] print(wb['login']['A5'].value) # None # 通过代码产生的excel表格必须经过人为操作之后才能读取出函数计算出来的值 res = wb['login'] print(res) # 返回一个生成器 gel = res.rows for i in ge1: for j in i: print(j.value) # 可以读出表中数据,空的地方为None
关于拷贝的前提:
import copy l = [1,2,[1,2]] l1 = l print(id(l),id(l1)) # 内存地址是一样的
浅拷贝:
l1 = copy.copy(l) # 拷贝一份...... l[0] = 222 print(l,l1) # 只有l改了值 l[2].append(666) print(l,l1) # 两个列表都改了值

深拷贝:
l1 = copy.deepcopy(l) l[2].append(666) print(l,l1) # [1,2,[1,2,666]] [1,2,[1,2]]

注意点:深浅拷贝的本质在于对于可变与不可变,到底是指向原来的值,还是自己新建的值

浙公网安备 33010602011771号