包,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()
start.py

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)()
src.py

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]]

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

posted @ 2019-07-21 18:00  泡泡茶壶i  阅读(230)  评论(0)    收藏  举报