包的使用

包的使用

什么是包

# 官方解释
Packages are a way of structuring Python’s module namespace by using “dotted module names”
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。

# 具体的:包是一系列模块的结合体,表示形式就是一个文件夹 该文件内部通常会有一个__init__.py文件,包的本质还是一个模块。

#需要强调的是:
  1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

  2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
  • 为何要使用包
包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来
随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性
  • 导入包的执行流程
# 首次导入包
	先产生一个执行文件的名称空间
		1. 创建包下面的__init__.py文件的名称空间
		2. 执行包下面的__init__.py文件中的代码,将产生的名字放入包下面的__init__.py文件名称空间中
		3. 在执行文件中拿到一个指向包下面的__init__.py文件名称空间的名字
  • 注意:
当作为包的设计者来说:
	1. 当模块的功能特别多的情况下 应该分文件管理
	2. 每个模块之间为了避免后期模块改名问题 可以使用相对导入(包里面的文件都应该是被导入的模块)

站在包的开发者来说  如果使用绝对路径来管理自己的模块 那么它只需要永远以包的路径为基准一次导入模块
站在包的使用者来说  必须将包所在的文件夹路径添加至系统环境变量中

logging模块

  • 日志级别
import logging
logging.debug('debug日志')
logging.info('info日志')
logging.warning('warning日志')
logging.error('error日志')
logging.critical('critical日志')

默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING
(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。
  • 日志对象
1. logger对象:负责产生日志
2. filter对象:过滤日志
3. handler对象:控制日志输出的位置
4. formater对象:规定日志内容的格式

灵活配置日志级别,日志格式,输出位置:

import logging

file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    handlers=[file_handler,],
    level=logging.ERROR
)

logging.error('你好')

日志切割

import time
import logging
from logging import handlers

sh = logging.StreamHandler()
rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024,backupCount=5)
fh = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    handlers=[fh,sh,rh],
    level=logging.ERROR
)

for i in range(1,100000):
    time.sleep(1)
    logging.error('KeyboardInterrupt error %s'%str(i))

配置参数

logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),
默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息

logger对象配置

import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8') 

# 再创建一个handler,用于输出到控制台 
ch = logging.StreamHandler() 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)

fh.setFormatter(formatter) 
ch.setFormatter(formatter) 
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 
logger.addHandler(ch) 

logger.debug('logger debug message') 
logger.info('logger info message') 
logger.warning('logger warning message') 
logger.error('logger error message') 
logger.critical('logger critical message')

hashlib模块

  • 算法介绍
Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。

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

摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。

摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:

import hashlib

md5 = hashlib.md5()				# 生成一个帮助造密文的对象
md5.update('how to use md5 in python hashlib?')	# 往对象里面传明文数据 update只能接受bytes类型的数据
print md5.hexdigest()			        # 获取明文数据对应的密文   

计算结果如下:
5d41402abc4b2a76b9719d911017c592

MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:
import hashlib
 
sha1 = hashlib.sha1()
sha1.update('how to use sha1 in ')
sha1.update('python hashlib?')
print sha1.hexdigest()

SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长
  • 应用场景
# hashlib模块应用场景
    1.密码的密文存储
    2.效验文件内容是否一致
  • 加盐处理

    由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”

def get_md5(data):							# 封装成函数方便下次调用
    md = hashlib.md5()						        # 使用md5的加密方式
    md.update('自己加的盐'.encode('utf-8'))                              # 将对象中传入自己加的盐
    md.update(data.encode('utf-8'))			                # 将函数中传参传入对象中
    return md.hexdigest()					        # 获取明文数据对应的密文
password = input('清输出你需要加密的值>>>:')    
res = get_md5(password)						        # 将变量传入函数中直接调用
print(res)							        # 打印加密结果

openpyxl模块

  • 使用模块写文件
# openpyxl 比较火的操作excel的模块

"""
excel 03版本前后缀名叫 xlx
excel 03版本后后缀名叫 xlsx

xlwd    写excel
xlrt    读excel

xlwd和xlrt既支持03版本之前的excel文件也支持03版本之后的excel文件
openpyxl 只支持03版本会后的xlsx
"""

from openpyxl import Workbook
wb = Workbook                   	# 生成一个工作簿
wb1 = wb.create_sheet('index',0)  	# 创建表index表单页,控制表单位置
wb2 = wb.create_sheet('index1',2)  	# 创建表index1表单页,控制表单位置
wb1.title = 'login'                     # 修改表单页的名称为login


wb1.cell(row=6,column=3,value=888888)           # 在表单index的第六行第三列添加内容888
# wb1['A3'] = 666                 		# 在表单index的A3位置写入内容666
# wb1['A4'] = 444                 		# 在表单index的A4位置写入内容444
# wb1['A5'] = '=sum(A3:A4)'       		# 在表单A5位置对A3和A4进行求和

wb1.append(['username','age','hobby'])      # 添加表头
wb1.append(['jason',18,'study'])            # 对应表头添加内容
wb1.append(['tank',11,'read'])              # 对应表头添加内容
wb1.append(['agon',22,'女教练'])             # 对应表头添加内容

wb.save('test,xlsx')                         # 保存工作簿起名为test
  • 读文件
from openpyxl import load_workbook                              # 读文件

wb = load_workbook('test.xlsx',read_only=True,data_only=True)   # data_only表示只读数据,不读公式
print(wb.sheetnames)                                            # 打印表单页名称
print(wb['login']['A3'].value)                                  # 查看表单页login A3位置对应的值
print(wb['login']['A5'].value)                                  # 查看表单页login A3位置对应的值

res = wb['login']
ge1 = res.rows
for i in ge1:
    for j in i:
        print(j.value)

copy模块

import copy
# l = [1,3,[1,2]]
# l1 = copy.copy(l)         # 拷贝一份,浅拷贝
# print(id(l),id(l1))       # 2123774630408 2123774630472 拷贝出来的文件与源文件di并不一致
# # l[0] = 222              # 仅针对l的索引0修改数据
# # print(l,l1)             # [222, 3, [1, 2]] [1, 3, [1, 2]]
# l[2].append(666)          #
# print(l,l1)               # [1, 3, [1, 2, 666]] [1, 3, [1, 2, 666]]

# 浅拷贝说明:
#仅仅是拷贝了一份和源文件同样的数据,但是实则上指向的内容还是和源文件一致,针对源文件进行修改,如上例,如修改源文件,针对不可变类型,源文件会断掉指向内容的值重新指向,而可变类型

l = [1,2,[1,2]]
l1 = copy.deepcopy(l)
l[2].append(666)
print(l,l1)                     # [1, 2, [1, 2, 666]] [1, 2, [1, 2]] 深拷贝,源文件新增,新文件并不修改

# 深拷贝说明:
#拷贝和源文件一样的数据,但是和浅拷贝不一样之处在于,深拷贝对于可变类型会新建内容,再将内容进行指向,这样对于源文件的可变类型修改,并不会改变新文件
#对于可变不可变到底是指向原来的内容,还是新建内容
原文地址:https://www.cnblogs.com/tcy1/p/14506219.html