zoukankan      html  css  js  c++  java
  • 包、logging模块、hashlib加密模块、openpyxl模块、深浅拷贝

    一、什么是包?

    1.1包是一系列模块文件的总和,就是一个文件夹。该文件夹通常(python3和python的区别)会有一个init文件,包的本质还是一个模块

    1.2具体的:包就是一个包含有__init__文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来

    需要强调的是:
      1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
    
      2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
    

    1.3首先看一下之前导入模块,做的事情:

    1.先产生一个执行文件的名称空间
    2.创建模块文件中的名称空间
    3.执行模块文件的代码,将名字放入模块文件的名称空间
    4.执行文件中拿到一个指向模块名称空间的名字
    

    1.4那看下调用包发生的事情吧:

    1.产生一个执行文件的名称空间
    2.创建包下面的__init__.py文件的名称空间
    3.执行包下面的__init__.py文件中的代码,将产生的名字放入该名称空间中
    4.在执行文件拿到一个指向包下面__init__.py文件名称空间的名字。
    

    1.5注意事项:

    1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

    2、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

    当你作为包的设计者来说
    1.当模块的功能特别多的情况下 应该分文件管理
    2.每个模块之间为了避免后期模块改名的问题 你可以使用相对导入(包里面的文件都应该是被导入的模块)

    1.6包的嵌套:

    只需把导入模块写入到嵌套的init文件文件中,这样外层文件要导入嵌套的模块只需要导入该init文件即可。

    1563527080985

    相对导入

    当存在多及嵌套的包。如果外层的包修改了名字,那么之前在init文件中建立的"绝对路径"全部失效。这时候可以使用“相对导入”,之前提到“相对导入”只能到导入模块中使用,而包就是给人家用的,因此可用。

    二、logging模块(瞜一眼):

    日志模块记录各种状态。比如某人眨眼睛等

    导入日志模块:import logging

    2.1日志有五个等级

    logging.debug('调试日志,记录简单的东西')  # 10
    logging.info('info日志,也是简单的日志')  # 20
    logging.warning('warning日志')  # 30
    logging.error('error日志,错误信息,但程序还能跑')  # 40
    logging.critical('critical日志,严重错误')  # 50
    
    如何生成日志?copy过来即可
    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',#p是上下午
                        level=30,#级别,比30大的都会记录
                        )#这么多参数瞄一眼,不需要记住
    #
    #
    logging.debug('debug日志')  # 10
    logging.info('info日志')  # 20
    logging.warning('warning日志')  # 30
    logging.error('error日志')  # 40
    logging.critical('critical日志')  # 50
    

    在pycharm中运行该程序,发现终端什么都没有,但是忽略了左边,左侧目录产生了一个access.log的文件,里面记录着等级信息。

    但接下来出现了问题:

    1.乱码;2.日志格式3.如何既打印到终端?

    回答3.了解知识点(该方式课内没有实现):在logging.basicConfig中将stream=True写入参数,并将filename=‘access.log’参数去掉,一山不容二虎。

    增加一个知识点:如何既打印到终端又写到文件中?(依据上述的方法,无法实现)

    接下来了解logging模块的四个对象((简单的日志)使用流程:8步,费事不讨好):

    参数中的level是控制输出的,大于该阈值的结果会记录下来

    1.logger对象:负责产生日志。logger.getLogger()方法填写日志的名字
    logger=logging.getLogger('转账记录')#写日志相关的名字,即产生的日志内的名字
    
    2.filter对象:过滤日志(了解即可,不怎么用,只需记得)
    3.handler对象:控制日志输出的位置(存放到文件/终端)可以有多个

    如下是输出到a1、a2文件和输出到终端。通过logging.FileHandler()方法和logging.StreamHandler()输出到终端和屏幕

    hd1=logging.FileHandler('a1.log',encoding='utf-8')##输出到终端(文件名字)(之前因为乱码,所以这里指定编码)
    hd2=logging.FileHandler('a2.log',encoding='utf-8')##输出到终端(文件名字)(之前因为乱码,所以这里指定编码)
    hd3=logging.StreamHandler()#指定多个handler对象,输出的终端
    
    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对象:addHandler()

    三个addHandler,代表logger传给三个对象,如下图是两个

    logger.addHandler(hd1)
    logger.addHandler(hd2)
    logger.addHandler(hd3)
    
    六、给handler绑定输出格式(formmate).setFmatter()方式
    hd1.setFormatter(fm1)
    hd2.setFormatter(fm2)
    
    七、设置日志等级.setLevel()
    logger.setLevel(20)
    
    八、写日志.debug()
    logger.debug('写了半天好累啊')
    
    日志运行流程图

    1563592266264

    现在将上面的内容整合成在一起(瞜一眼 )
    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对象指定输出位置
    logger.addHandler(hd1)
    logger.addHandler(hd2)
    logger.addHandler(hd3)
    
    # 6.给handler绑定formmate对象。即给输出位置绑定输出内容的格式
    hd1.setFormatter(fm1)
    hd2.setFormatter(fm2)
    hd3.setFormatter(fm2)
    
    # 7.设置日志等级
    logger.setLevel(10)
    
    # 8.记录日志
    logger.debug('写了半天 好累啊 好热啊 好想释放')
    

    总结:写完这么一大堆代码就实现了这么点功能,费事不讨好。配置字典

    三、logging配置字典(了解)

    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)
    #用os模块创建一个出来
    # 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,#如果上面文件满了就直接新建一个5M的文件,最多存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')#必须注意该名字必须在上面的logger中定义,否则无内容记录。因此直接将上面的logger内不要定义名字,直接写空即可,程序会自动添加名字
    logger1.debug('好好的 不要浮躁 努力就有收获')
    

    搞了 这么多,只需掌握最后的三句话:

    logging.config.dictConfig(LOGGING_DIC)  # (字典名)自动加载字典中的配置
    
    #接下来生成一个对象
    logger1 = logging.getLogger('fdsafsadfsa')#直接将上面的logger内不要定义名字,直接写空即可,程序会自动添加名字
    logger1.debug('好好的 不要浮躁 努力就有收获')
    

    四、hashlib模块

    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

    hashlib模块 加密的模块

    import hashlib  # 这个加密的过程是无法解密的
    md = hashlib.sha3_256()  # 生成一个帮你造密文的对象
    md.update('hello'.encode('utf-8'))  # 往对象里传明文数据  update只能接受bytes类型的数据
    md.update(b'Jason_@.')  # 往对象里传明文数据  update只能接受bytes类型的数据
    print(md.hexdigest())  # 获取明文数据对应的密文
    
    4.1撞库

    1.不同的算法 使用方法是相同的
    密文的长度越长 内部对应的算法越复杂
    但是
    1.时间消耗越长
    2.占用空间更大
    通常情况下使用md5算法 就可以足够了

    4.2hashlib模块应用场景

    ​ 1.密码的密文存储
    ​ 2.校验文件内容是否一致

    分多次传入内容,但是生成的密文还是一样的

    md = hashlib.md5()
    md.update(b'areyouok?')
    md.update(b'are')
    md.update(b'you')
    md.update(b'ok?')
    print(md.hexdigest())  # 408ac8c66b1e988ee8e2862edea06cc7
    408ac8c66b1e988ee8e2862edea06cc7
    
    4.3加盐处理
    import hashlib
    
    md = hashlib.md5()
    # 公司自己在每一个需要加密的数据之前 先手动添加一些内容
    md.update(b'oldboy.com')  # 加盐处理
    md.update(b'hello')  # 真正的内容
    print(md.hexdigest())
    
    4.4动态加盐
    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

    5.1写模块:Workbook()
    from openpyxl import Workbook
    wb = Workbook()  #先生成一个工作簿
    wb.save('test.xlsx')# 保存新建的excel文件
    
    5.2创建新的表单页.create_sheet()
    wb1 = wb.create_sheet('index',0)
    后面的索引控制表单创建的位置。默认是从1往后
    
    5.3修改表单页名称:.title
    wb1.title = 'login'
    
    5.4为表单赋值

    在新创建(wb1=wb.create_sheet('名称',索引))的表单页上填写数据

    wb1['A3'] = 666
    wb1['A4'] = 444
    

    指定具体某行某列的数据

    wb1.cell(row=6,column=3,value=88888888)
    

    加入函数功能

    wb1['A5'] = '=sum(A3:A4)'
    

    按照一行一行的顺序传值

    wb1.append(['username','age','hobby'])
    wb1.append(['jason',18,'study'])
    wb1.append(['tank',72,'吃生蚝'])
    wb1.append(['egon',84,'女教练'])
    wb1.append(['sean',23,'会所'])
    # 保存新建的excel文件
    # wb.save('test.xlsx')
    

    5.5openpyxl读文件load_workbook

    导入模块

    from openpyxl import load_workbook#读文件
    wb = load_workbook('test.xlsx',read_only=True,data_only=True)
    print(wb['login']['A3'].value)
    print(wb['login']['A4'].value)
    print(wb['login']['A5'].value)  # 通过代码产生的excel表格必须经过人为操作之后才能读取出函数计算出来的结果值
    
    res = wb['login']
    # print(res)
    ge1 = res.rows
    for i in ge1:
        for j in i:
            print(j.value)
    
    

    六、深浅拷贝

    6.1浅拷贝:copy.copy()

    l = [1,2,[1,2]]
    l1 = l
    print(id(l),id(l1))#得出内存地址相同
    l1 = copy.copy(l)  # 拷贝一份 ..  浅拷贝
    print(id(l),id(l1))
    #得出内存地址不相同。
    l[2].append(666)
    print(l,l1)
    #l1和l的打印结果相同
    #得出结论,当浅拷贝内容中出现可变类型数据,那么复制的内容是直接引用该可变类型的。
    

    6.2深拷贝

    l1=copy.deepcopy(l)
    print(l)
    l1[2].append(666)
    print(l1)
    """
    [1, 2, [1, 2]]
    [1, 2, [1, 2, 666]]
    """
    l1为可变类型的列表增加值,现在l不会一起发生变化了
    

    1563540886226

    1563541037258

    综合得出:深浅拷贝,

    不可变类型的值,一个发生变大,拷贝的那个必定发生变化。而

    可变类型的值,发生改变,只要模式为深拷贝的情况下,拷贝的那份才会发生变化

  • 相关阅读:
    51nod1693 水群
    51nod 1158 全是1的最大子矩阵
    poj1192 最优连通子集(树形dp)
    51nod 1051 最大子矩阵和(dp)
    codeforces723 D. Lakes in Berland(并查集)
    51nod 1065 最小正子段和
    poj1122 FDNY to the Rescue!(dij+反向建图+输出路径)
    51nod 1050 循环数组最大子段和
    hdu4781 Assignment For Princess(构造)
    51nod 1043 幸运号码(数位dp)
  • 原文地址:https://www.cnblogs.com/ZDQ1/p/11217352.html
Copyright © 2011-2022 走看看