包、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

综合得出:深浅拷贝,

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

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

原文地址:https://www.cnblogs.com/ZDQ1/p/11217352.html