包以及log日志
包的使用
官网解释
Packages are a way of structuring Python’s module namespace by using “dotted module names”
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。
具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来
需要强调的是:
-
在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
-
创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
-
import
# 第一类: 执行文件 通过 import 导入包以及包内的功能 # 创建一个aaa的包,自行创建一个__init__py文件 # 回忆 :创建一个tbjx模块发生的三件事: ''' 1. 将该tbjx文件加载到内存. 2. 创建一个以tbjx命名的名称空间. 3. 通过tbjx. 的方式引用tbjx模块的所有的名字. ''' # 创建一个包,也会发生三件事: ''' 1. 将该aaa包内 __init__py文件加载到内存. 2. 创建一个以aaa命名的名称空间. 3. 通过aaa. 的方式引用__init__的所有的名字. ''' import aaa # print(aaa.x) # aaa.f1() # print(aaa.m1) # print(aaa.m1.a) # 我想要引用 aaa包的m1文件的a变量 # 错误示例1: import aaa # 1. aaa的 __init__ 里面 写import m1 # 2. print(aaa.m1.a) # print(aaa.m1.a) # 报错原因: No module named 'm1' # 分析报错原因: 模块找不到 内存,内置,sys.path三个地方找不到. # m1 不在内存,不在内置,sys.path 会主动加载执行文件(包的使用.py)的当前目录. # 解决方式: import aaa # 1. 在执行文件写入 import aaa # 2. aaa的 __init__ 里面 写 from aaa import m1 # 3. 然后在执行文件 aaa.m1.a # print(aaa.m1.a) # aaa.m1.func1() import aaa # 如何在当前文件中,引用 aaa包的bbb包. # 1. 在执行文件写入 import aaa # 2. aaa的 __init__ 里面 写 from aaa import bbb # 3. 然后在执行文件 aaa.bbb # print(aaa.bbb) # 如何在当前文件中,引用 aaa包的bbb包 的 变量 name. # 1. 在执行文件写入 import aaa # 2. aaa的 __init__ 里面 写 from aaa import bbb # 3. 然后在执行文件 aaa.bbb # print(aaa.bbb) import aaa # print(aaa.bbb.name) # 如何在当前文件中,引用 aaa包的bbb包 的 mb文件的函数func. # 1. 在执行文件写入 import aaa # 2. 在aaa包的__Init__ 写上 from aaa import bbb (这样写 bbb包的__init__里面所有的名字都能引用) # print(aaa.bbb.name) # 3. 在bbb包的__Init__ 写上 from aaa.bbb import mb # aaa.bbb.mb.func3() # 首先 无论从哪里引用模块,import 或者 from ... import ... # 最开始的模块或者包名一定是内存,内置,sys.path中能找到的.(可参考bbb包中的 __init__) # 直接import 为了让我们会使用 包里面的 __init__ 第二类: 执行文件 通过 from ... import... 导入包以及包内的功能
-
from ... import ...
# from ... import ... # 通过这种方式不用设置__init__文件 # from aaa import m1 # m1.func() # from aaa.bbb.m2 import func1 # func1() # from aaa.bbb import m2 # m2.func1() # from a.b.c import d.e.f # c的. 的前面一定是包 # import 的后面一定是名字,并且不能 再有点 # from aaa.bbb.m2.func1 import a # 错误的 # from aaa.bbb import m2 # m2.func1() import json
-
相对导入与绝对导入
我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:
绝对导入:以glance作为起始
相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)
例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py
在glance/api/version.py #绝对导入 from glance.cmd import manage manage.main() #相对导入 from ..cmd import manage manage.main()
包以及包所包含的模块都是用来被导入的,而不是被直接执行的。而环境变量都是以执行文件为准的
比如我们想在glance/api/versions.py中导入glance/api/policy.py,有的同学一抽这俩模块是在同一个目录下,十分开心的就去做了,它直接这么做
#在version.py中 import policy policy.get()
没错,我们单独运行version.py是一点问题没有的,运行version.py的路径搜索就是从当前路径开始的,于是在导入policy时能在当前目录下找到
但是你想啊,你子包中的模块version.py极有可能是被一个glance包同一级别的其他文件导入,比如我们在于glance同级下的一个test.py文件中导入version.py,如下
from glance.api import versions ''' 执行结果: ImportError: No module named 'policy' ''' ''' 分析: 此时我们导入versions在versions.py中执行 import policy需要找从sys.path也就是从当前目录找policy.py, 这必然是找不到的 '''
相对导入和绝对导入的总结
绝对导入与相对导入 # 绝对导入: 以执行文件的sys.path为起始点开始导入,称之为绝对导入 # 优点: 执行文件与被导入的模块中都可以使用 # 缺点: 所有导入都是以sys.path为起始点,导入麻烦 # 相对导入: 参照当前所在文件的文件夹为起始开始查找,称之为相对导入 # 符号: .代表当前所在文件的文件加,..代表上一级文件夹,...代表上一级的上一级文件夹 # 优点: 导入更加简单 # 缺点: 只能在导入包中的模块时才能使用 #注意: 1. 相对导入只能用于包内部模块之间的相互导入,导入者与被导入者都必须存在于一个包内 2. attempted relative import beyond top-level package # 试图在顶级包之外使用相对导入是错误的,言外之意,必须在顶级包内使用相对导入,每增加一个.代表跳到上一级文件夹,而上一级不应该超出顶级包
工作日志分四个大类:
- 系统日志:记录服务器的一些重要信息:监控系统,cpu温度,网卡流量,重要的硬件的一些指标,运维人员经常使用的,运维人员,记录操作的一些指令.
- 网站日志: 访问异常,卡顿,网站一些板块,受欢迎程度,访问量,点击率.等等,蜘蛛爬取次数等等.
- 辅助开发日志: 开发人员在开发项目中,利用日志进行排错,排除一些避免不了的错误(记录),辅助开发.
- 记录用户信息日志: 用户的消费习惯,新闻偏好,等等.(数据库解决)
日志模块
旗舰版日志
"""
logging配置
"""
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_name = 'login.log' # log文件名
logfile_path_staff = r'E:\老男孩学习\JiaoXueJiHua\day19\day19\日志模块\staff.log'
logfile_path_boss = r'E:\老男孩学习\JiaoXueJiHua\day19\day19\日志模块\boss.log'
logfile_path_login = r'E:\老男孩学习\JiaoXueJiHua\day19\day19\日志模块\login.log'
# log配置字典
# LOGGING_DIC第一层的所有的键不能改变
LOGGING_DIC = {
'version': 1, # 版本号
'disable_existing_loggers': False, # 固定写法
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
'id_simple':{
'format': id_simple_format
}
},
'filters': {},#过滤
'handlers': {
#打印到终端的日志
'sh': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'id_simple'
},
#打印到文件的日志,收集info及以上的日志
'fh': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path_staff, # 日志文件
'maxBytes': 5000, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
'boss':
{
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'id_simple',
'filename': logfile_path_boss, # 日志文件
'maxBytes': 5000, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['sh', 'fh', 'boss'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
},
}
def md_logger():
logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger("login.log") # 生成一个log实例
return logger
logger.debug('It works!') # 记录该文件的运行状态
dic = {
'username': '小黑'
}
def login():
# print('登陆成功')
md_logger().info(f"{dic['username']}登陆成功")
#
# def aricle():
# print('欢迎访问文章页面')
login()
# aricle()
Low版(文件与屏幕输入只能选择一个)
# import logging
# logging.basicConfig(
# level=logging.DEBUG,
# )
# # logging.debug('debug message')
# # logging.info('info message')
# # logging.warning('warning message')
# # logging.error('error message')
# # logging.critical('critical message')
# 应用:
# def func():
# print('in func')
# logging.debug('正常执行')
# func()
# try:
# i = input('请输入选项:')
# int(i)
# except Exception as e:
# logging.error(e)
# print(11)
# low版的日志:缺点: 文件与屏幕输入只能选择一个.
import logging
logging.basicConfig(
# level=logging.DEBUG,
level=30,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
filename=r'test.log',
)
# logging.debug('调试模式') # 10
# logging.info('正常模式') # 20
logging.warning('警告信息') # 30
# logging.error('错误信息') # 40
# logging.critical('严重错误信息') # 50
标配版日志(文件和屏幕)
# import logging
#
# # 创建一个logging对象
# logger = logging.getLogger()
#
# # 创建一个文件对象
# fh = logging.FileHandler('标配版.log', encoding='utf-8')
#
# # 创建一个屏幕对象
# sh = logging.StreamHandler()
#
# # 配置显示格式
# formatter1 = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
# formatter2 = logging.Formatter('%(asctime)s %(message)s')
# fh.setFormatter(formatter1)
# sh.setFormatter(formatter2)
#
# logger.addHandler(fh)
# logger.addHandler(sh)
#
# # 总开关
# logger.setLevel(10)
#
# fh.setLevel(10)
# sh.setLevel(40)
#
# logging.debug('调试模式') # 10
# logging.info('正常模式') # 20
# logging.warning('警告信息') # 30
# logging.error('错误信息') # 40
# logging.critical('严重错误信息') # 50