# coding:utf-8
"""
模块
三种来源
1.内置的
2.第三方的
3.自定义的
四种表示形式
1.py文件(******)
2.共享库
3.文件夹(一系列模块的结合体)(******)
4.C++编译的连接到python内置的
"""
# 研究模块与包 还可以站另外两个角度分析不同的问题
# 1.模块的开发者
# 2.模块的使用者
"""
执行文件调用导入模块时发生的几件事:
先产生一个执行文件的名称空间
1.创建模块文件的名称空间
2.执行模块文件中的代码 将产生的名字放入模块的名称空间中
3.在执行文件中拿到一个指向模块名称空间的名字
"""
"""
什么是包?
它是一系列模块文件的结合体,表示形式就是一个文件夹
该文件夹内部通常会有一个__init__.py文件
包的本质还是一个模块
"""
# from dir.dir1 import p
"""
执行文件导入包,发生的几件事情:
首次导入包:
先产生一个执行文件的名称空间
1.创建包下面的__init__.py文件的名称空间
2.执行包下面的__init__.py文件中的代码 将产生的名字放入包下面的__init__.py文件名称空间中
3.在执行文件中拿到一个指向包下面的__init__.py文件名称空间的名字
在导入语句中 .号的左边肯定是一个包(文件夹)
当你作为包的设计者来说
1.当模块的功能特别多的情况下 应该分文件管理
2.每个模块之间为了避免后期模块改名的问题 你可以使用相对导入(包里面的文件都应该是被导入的模块)
站在包的开发者 如果使用绝对路径来管理的自己的模块 那么它只需要永远以包的路径为基准依次导入模块
站在包的使用者 你必须得将包所在的那个文件夹路径添加到system path中(******)
python2如果要导入包 包下面必须要有__init__.py文件
python3如果要导入包 包下面没有__init__.py文件也不会报错
当你在删程序不必要的文件的时候 千万不要随意删除__init__.py文件
"""
'''
logging模块的使用
日志的等级 级别高低根据数值排序
logging.debug('debug日志') # 10
logging.info('info日志') # 20
logging.warning('warning日志') # 30
logging.error('error日志') # 40
logging.critical('critical日志') # 50
'''
# 日志模块:记录
# 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=30,
# )
#
#
# logging.debug('debug日志') # 10
# logging.info('info日志') # 20
# logging.warning('warning日志') # 30
# logging.error('error日志') # 40
# logging.critical('critical日志') # 50
"""
1.乱码
2.日志格式
3.如何既打印到终端又写到文件中
"""
# 日志分为五个等级 等级:地震的强度
"""
log生成的几个关键流程 ;
1.logger对象:负责产生日志
2.filter对象:过滤日志(了解)
3.handler对象:控制日志输出的位置(文件/终端)
4.formmater对象:规定日志内容的格式
生成日志的步骤
一 import logging # 导入模块
二 日志对象 = logging.getLogger('日志功能名称')
三 handler对象 = logging.FileHandler('日志文件名加后缀在当前路径下',encoding='utf-8') 指定字符编码,支持中文
handler对象 = logging.StreamHandler() # 输出到终端
四 formmater对象 = logging.Formatter(
fmt='字符串形式的当前时间-logger名-文本形式的日志级别-调用日志输出函数的模块名 : 用户输出的消息',
datefmt='年-月-日 时:分:秒 上午下午',
)
fm1 = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
)
五 给日志对象绑定handler对象,给日志对象绑定输出对象,指定日志输出的文件,字符集
日志对象.addHandler(handler对象)
六 给handler绑定formmate对象,给日志输出对象绑定日志输出格式,只当日志文件或者终端以什么样的格式输出
handler对象.setFormatter(formmater对象)
七 指定日志输出级别,大于等于该级别输出,小于该级别不输出
logger.setLevel(10)
八 记录日志
logger.日志级别('日志输出内容')
"""
#
# import logging # 导入模块
#
# # 1.logger对象:负责产生日志
# logger = logging.getLogger('转账记录') # 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(fm1)
#
# # 7.设置日志等级
# logger.setLevel(20)
#
# # 8.记录日志
# logger.info('写了半天 好累啊 好热啊 好想释放')
'''
# 日志的配置字典
# 使用日志字典配置
一 import os # 导入os模块跟操作系统打交道,创建目录文件等
二 import logging.config # 到入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'
设置变量,拼接字符串,显示日志格式,两种格式一种全面一种精简
四 logfile_dir = os.path.dirname(__file__) # log文件的目录 就在执行文件同级目录,就找父目录就可以了,一层
五 logfile_name = '日志文件名.log' # log文件名
# 如果不存在定义的日志目录就创建一个
六 if not os.path.isdir(logfile_dir): # 如果日志目录不存在
os.mkdir(logfile_dir) # 日志目录不存在就创建一个
七 logfile_path = os.path.join(logfile_dir, logfile_name)
# 拼接日志文件以及其路径,拼接绝对路径,后面指定输入文件需要用这个变量
*** 四五六七日志文件目录,文件名,拼接文件绝对路径,需要自己手动设置
# log配置字典
八 LOGGING_DIC = {
九 'version': 1,
十 'disable_existing_loggers': False,
十一 'formatters': { # 指定两个日志输出格式 standard simple
'standard': {
'format': standard_format # 给其赋值为变量,变量为第三步定义的输出格式,这里用变量方便后期修改
},
'simple': {
'format': simple_format
},
},
十二 'filters': {}, # 'filters 过滤日志
十三 'handlers': {
#打印到终端的日志
'console': { # console 终端
'level': 'DEBUG', # 终端的日志级别
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple' # 指定输出格式 simple 需要跟上面指定的key名字一致
},
#打印到文件的日志,收集info及以上的日志
'default': { # default 默认打印到文件中
'level': 'DEBUG', # 输入文件的日志级别
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard', # 指定保存到文件的日志输出格式 standard 需要跟上面指定的一致
'filename': logfile_path, # 日志文件以及其路径
'maxBytes': 1024*1024*5, # 日志大小 5M 设置日志最大上限
'backupCount': 5, # 最多五个日志文件
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
十四 'loggers': { # 产生log的步骤
#logging.getLogger(__name__)拿到的logger配置
'日志功能名字': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # 执行输出的日志等级,大于等于10的都输出,可以指定info,大于等于20输出
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 默认都会使用该k:v配置
},
}
十五 logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置 LOGGING_DIC 是配置好的字典
十六 logger1 = logging.getLogger('日志功能名字') # 上面第十四步设置的名字
十七 logger1.debug('好好的 不要浮躁 努力就有收获') # 输出日志内容 debug级别日志,可以修改
'''
# 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'
#
#
#
# # 定义日志输出格式 结束
# """
# 下面的两个变量对应的值 需要你手动修改
# """
# 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
# },
# },
# 'filters': {}, # 过滤日志
# 'handlers': {
# #打印到终端的日志
# 'console': {
# 'level': 'DEBUG',
# 'class': 'logging.StreamHandler', # 打印到屏幕
# 'formatter': 'simple'
# },
# #打印到文件的日志,收集info及以上的日志
# 'default': {
# 'level': 'DEBUG',
# 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
# 'formatter': 'standard',
# 'filename': logfile_path, # 日志文件
# 'maxBytes': 1024*1024*5, # 日志大小 5M
# 'backupCount': 5,
# 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
# },
# },
# 'loggers': {
# #logging.getLogger(__name__)拿到的logger配置
# '': {
# 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'DEBUG',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 默认都会使用该k:v配置
# },
# }
#
# # 使用日志字典配置
# logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
# logger1 = logging.getLogger('asajdjdskaj')
# logger1.debug('好好的 不要浮躁 努力就有收获')
'''
# hashlib模块 加密的模块
这个加密的过程是无法解密的
传入的内容 可以分多次传入 只要传入的内容相同 那么生成的密文肯定相同
import hashlib # 导入模块
md = hashlib.md5() # 生成一个帮你造密文的对象,加密的工厂,加密模式是md5,可以换别的sha3_256()等
md.update(b'xiao') # 加盐处理 公司自己在每一个需要加密的数据之前,先手动添加一些内容,可以是每次不一样的内容
md.update('hello'.encode('utf-8')) # 往对象里传的是明文数据 update只能接受bytes类型的数据,需要encode
md.update(b'hello') # 往对象里传的是明文数据 update只能接受bytes类型的数据,需要encode
以上三次update都是往造密文的对象中添加明文内容,分多次传入跟一次传入是一样的,下面获取的密文是三个明文的结果
print(md.hexdigest()) # 获取明文数据对应的密文 # 打印加密之后的到的MD5值
应用:
可以写成一个加密函数,获取密文的函数,将用户注册输入的密码加密存储,登录时再调函数,加密明文再和存储做密文比较
import hashlib
def get_md5(data):
md = hashlib.md5()
md.update('加盐'.encode('utf-8'))
md.update(data.encode('utf-8'))
return md.hexdigest()
password = input('password>>>:')
res = get_md5(password)
print(res)
'''
# import hashlib # 这个加密的过程是无法解密的
# md = hashlib.sha3_256() # 生成一个帮你造密文的对象
# # md.update('hello'.encode('utf-8')) # 往对象里传明文数据 update只能接受bytes类型的数据
# md.update(b'Jason_@.') # 往对象里传明文数据 update只能接受bytes类型的数据
# print(md.hexdigest()) # 获取明文数据对应的密文
# 撞库
"""
1.不用的算法 使用方法是相同的
密文的长度越长 内部对应的算法越复杂
但是
1.时间消耗越长
2.占用空间更大
通常情况下使用md5算法 就可以足够了
"""
# import hashlib
# # 传入的内容 可以分多次传入 只要传入的内容相同 那么生成的密文肯定相同
# md = hashlib.md5()
# md.update(b'areyouok?')
# md.update(b'are')
# md.update(b'you')
# md.update(b'ok?')
# print(md.hexdigest()) # 408ac8c66b1e988ee8e2862edea06cc7
# 408ac8c66b1e988ee8e2862edea06cc7
"""
hashlib模块应用场景
1.密码的密文存储
2.校验文件内容是否一致
"""
# 加盐处理
# import hashlib
#
# md = hashlib.md5()
# # 公司自己在每一个需要加密的数据之前 先手动添加一些内容
# md.update(b'oldboy.com') # 加盐处理
# md.update(b'hello') # 真正的内容
# print(md.hexdigest())
# 动态加盐
# import hashlib
#
# def get_md5(data):
# md = hashlib.md5()
# md.update('加盐'.encode('utf-8'))
# md.update(data.encode('utf-8'))
# return md.hexdigest()
#
#
# password = input('password>>>:')
# res = get_md5(password)
# print(res)
'''
# openpyxl 比较火的操作excel表格的模块
'''
"""
03版本之前 excel文件的后缀名 叫xls
03版本之后 excel文件的后缀名 叫xlsx
xlwd 写excel
xlrt 读excel
xlwd和xlrt既支持03版本之前的excel文件也支持03版本之后的excel文件
openpyxl 只支持03版本之后的 xlsx
写文件
from openpyxl import Workbook # 导入工作簿的写功能
工作簿名 = Workbook() # 先生成一个工作簿 会创建一个
工作簿名 = wb.create_sheet('sheet名',从0开始第几个sheet) # 创建一个表单页 后面可以通过数字控制位置
sheet.title = '新sheet名' # 后期可以通过表单页对象点title修改表单页名称
工作簿名['A3'] = 值 # A列第三行
工作簿名['A5'] = '=sum(A3:A4)' # excel求和函数 # A列第五行
工作簿名.cell(row=6,column=3,value=88888888) # 根据坐标添加值
工作簿名.append(['值1','值2','值3']) # 添加到第一行的ABC
工作簿名.save('文件名.xlsx') # 保存表格和内容,并指定文件名 另存为
读文件
from openpyxl import load_workbook # 导入工作簿的读功能
wb = load_workbook('test.xlsx',read_only=True,data_only=True)
print(wb.sheetnames) # ['login', 'Sheet', 'index1'] 看表格里面都有那些sheet,并返回列表
print(wb['login']['A3'].value) # 打印 (指定文件的指定sheet的指定坐标的.value值) 取值
print(wb['login']['A5'].value) # 通过代码产生的excel表格必须经过人为操作之后才能读取出函数计算出来的结果值 A5是函数
# res = wb['login']
# # print(res)
# ge1 = res.rows
# for i in ge1:
# for j in i:
# print(j.value)
"""
# 写
# from openpyxl import Workbook
#
#
# wb = Workbook() # 先生成一个工作簿
# wb1 = wb.create_sheet('index',0) # 创建一个表单页 后面可以通过数字控制位置
# wb2 = wb.create_sheet('index1')
# wb1.title = 'login' # 后期可以通过表单页对象点title修改表单页名称
#
# wb1['A3'] = 666
# wb1['A4'] = 444
# wb1.cell(row=6,column=3,value=88888888)
# wb1['A5'] = '=sum(A3:A4)'
#
# wb2['G6'] = 999
# wb1.append(['username','age','hobby'])
# wb1.append(['jason',18,'study'])
# wb1.append(['tank',72,'吃生蚝'])
# wb1.append(['egon',84,'女教练'])
# wb1.append(['sean',23,'会所'])
# wb1.append(['nick',28,])
# wb1.append(['nick','','秃头'])
# 保存新建的excel文件
# wb.save('test.xlsx')
# from openpyxl import load_workbook # 读文件
#
#
# wb = load_workbook('test.xlsx',read_only=True,data_only=True)
# # print(wb)
# # print(wb.sheetnames) # ['login', 'Sheet', 'index1']
# # print(wb['login']['A3'].value)
# # print(wb['login']['A4'].value)
# # print(wb['login']['A5'].value) # 通过代码产生的excel表格必须经过人为操作之后才能读取出函数计算出来的结果值
#
# wb = load_workbook('test.xlsx',read_only=True,data_only=True)
# res = wb['login']
# # print(res)
# ge1 = res.rows
# for i in ge1:
# for j in i:
# print(j.value)
'''
深浅拷贝
深浅拷贝对于不可变类型,原数据和副本都指向同一内存地址中的值
深浅拷贝的区别在于对于不可变类型,指向原来(浅拷贝),还是自己创建一个新的可变类型(深拷贝)
浅拷贝:副本 = copy.copy(原数据) 之后
原数据中的不可变类型跟副本中的不可变类型在内存中是同一个值
副本中的不可变类型还是指向原数据指向的内存中的值
原数据中的可变类型跟副本中的可变类型在内存中是同一个值
副本中的可变类型也还是指向原数据指向的内存中的值
修改原数据中不可变类型,副本数据不变
修改原数据中可变类型,副本数据也会变
深拷贝:副本 = copy.deepcopy(原数据) 之后,
原数据中的不可变类型跟副本中的不可变类型在内存中是同一个值
副本中的不可变类型还是指向原数据指向的内存中的值
原数据中的可变类型跟副本中的可变类型在内存中是不同的两个值
副本中的可变类型会新建一个根源数据一样的不可变类型,可变类型中的不可变类型还是指向原数据
修改原数据中不可变类型,副本数据不变
修改原数据中可变类型,副本数据不会变
修改原数据的可变类型的不可变类型,副本数据可变类型中的不可变类型会一起改变
'''
# import copy
# l = [1,2,[1,2]]
# l1 = l
# print(id(l),id(l1))
# l1 = copy.copy(l) # 拷贝一份 ....... 浅拷贝
# print(id(l),id(l1))
# l[0] = 222
# print(l,l1)
# l[2].append(666)
# print(l,l1)
# l1 = copy.deepcopy(l)
# l[2].append(666)
# print(l,l1)