什么是包?
它是一系列模块文件的集合体,表现形式就是一个文件夹
内部通常都会有一个__init__.py文件
包的本质还是一个模块
为什么要使用包?
包的本质是一个文件夹形式的模块,他的唯一功能就是将文件组织起来,随着功能越写越多,我们不可能将所有功能都放在一个py文件中,于是我们使用模块来组织功能,随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性
首次导入包发生的三件事
先产生一个执行文件的名称空间,导入包
1.先创建包下面的__init__.py文件的名称空间
2.执行包下面的__init__.py文件的代码,将产生的名字存放在__init__.py文件的名称空间中
3.在执行文件中拿到一个指向包下面__init__.py文件的名称空间的名字
绝对导入和相对导入的选用:
当作为包的设计者来说
1.当模块的功能很多的情况下,应该分文件管理
2.每个模块之间为了避免后期模块改名的问题,需要使用相对导入(包里的文件都应该是可导入的模块)
绝对路径和相对路径的选用:
站在包的开发者:如果使用绝对路径来管理自己的模块,它只需永远以包的路径为基准依次导入模块
站在包的使用者:必须将包所在的文件夹路径添加到system path中
1 # 包中的代码块 2 from day1701.p1 import p2 # 导入p2这个包,从p2里的__init__拿数据 3 p2.f1() # p2包中根据已导入的模块取出函数f1 4 p2.f3() # p2包中根据已导入的模块取出函数f3
1 # __init__.py文件中的模块导入代码块 2 from day1701.p1.p2.m1 import f1 # 绝对导入,以执行文件的位置为准 3 from .m3 import f3 # 相对导入,以该文件的位置为基准
需要注意的是:在导入语句中 .号的左边肯定是一个包(文件夹)
python2和python3中的区别
python2如果要导入包,包下面必须要有__init__文件
python3如果要导入包,包下面没有__init__文件也不会报错
所以我们在删除文件的时候不能把__init__文件删除,哪怕是他里边没有内容
2.logging模块
日志模块:用来记录程序运行信息的模块
日志模块的等级
1 # logging日志模块 2 import logging 3 logging.basicConfig(filename='access.log', 4 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 5 datefmt='%Y-%m-%d %H:%M:%S %p', 6 level=30 7 ) 8 # 日志模块的等级 9 logging.debug('debug日志') # 10 10 logging.info('info日志') # 20 11 logging.warning('warning日志') # 30 12 logging.error('error日志') # 40 13 logging.critical('critical日志') # 50 14 # 等级由上到下越来越高
需要解决三个问题
1.乱码
2.日志格式问题
3.如何既打印到终端又写到文件中
输出日志的八个步骤
1 import logging 2 # 1.logger对象:负责产生日志 3 logger = logging.getLogger('转账记录') 4 5 # 2.filter对象:过滤日志(了解) 6 7 # 3.handler对象:控制日志输出的位置(文件或者终端) 8 hd1 = logging.FileHandler('a1.log',encoding='utf-8') # 输出到文件 9 hd2 = logging.StreamHandler() # 输出到终端 10 11 # 4.formatter对象:规定日志内容的格式 12 fm1 = logging.Formatter( 13 fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 14 datefmt='%Y-%m-%d %H:%M:%S %p' 15 ) 16 fm2 = logging.Formatter( 17 fmt='%(asctime)s - %(name)s : %(message)s', 18 datefmt='%Y-%m-%d' 19 ) 20 21 # 5.给logger对象绑定handler对象 22 logger.addHandler(hd1) 23 logger.addHandler(hd2) 24 25 # 6.给handler绑定formatter对象 26 hd1.setFormatter(fm1) 27 hd2.setFormatter(fm2) 28 29 # 7.设置日志等级 30 logger.setLevel(10) 31 32 # 8.记录日志 33 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) # 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配置 '': { # 当键不存在的情况下 默认都会使用该k:v配置 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, }, } # 使用日志字典配置,这个也需要自己配置 logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置 logger1 = logging.getLogger('记录') logger1.debug('日志字典配置的使用')