• 包以及日志的初识和使用


    包以及log日志

    包的使用

    官网解释

    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. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块

    3. 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... 导入包以及包内的功能
      
    4. 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
      
    5. 相对导入与绝对导入

      我们的最顶级包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 # 试图在顶级包之外使用相对导入是错误的,言外之意,必须在顶级包内使用相对导入,每增加一个.代表跳到上一级文件夹,而上一级不应该超出顶级包
      

    工作日志分四个大类:

    1. 系统日志:记录服务器的一些重要信息:监控系统,cpu温度,网卡流量,重要的硬件的一些指标,运维人员经常使用的,运维人员,记录操作的一些指令.
    2. 网站日志: 访问异常,卡顿,网站一些板块,受欢迎程度,访问量,点击率.等等,蜘蛛爬取次数等等.
    3. 辅助开发日志: 开发人员在开发项目中,利用日志进行排错,排除一些避免不了的错误(记录),辅助开发.
    4. 记录用户信息日志: 用户的消费习惯,新闻偏好,等等.(数据库解决)

    日志模块

    旗舰版日志
    """
    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:老男孩学习JiaoXueJiHuaday19day19日志模块staff.log'
    logfile_path_boss = r'E:老男孩学习JiaoXueJiHuaday19day19日志模块oss.log'
    logfile_path_login = r'E:老男孩学习JiaoXueJiHuaday19day19日志模块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
    
  • 相关阅读:
    Java判断一个实体类对象实例的所有成员变量是否为空
    正则表达式 整数
    将定时任务cron 解析成中文
    如何使用html定义一个红色小圆点
    Oracle获取当前日期前一个月的全部日期
    京东系统架构师如何让笨重的架构变得灵巧
    POI使用详解
    Java Excel 列号数字与字母互相转换
    使用exe4j将java项目打成exe执行程序
    Address already in use: JVM_Bind错误的解决
  • 原文地址:https://www.cnblogs.com/-777/p/11116580.html
Copyright © 2020-2023  润新知