zoukankan      html  css  js  c++  java
  • 17.Python略有小成(包,logging模块)

    Python(包,logging模块)

    一、包

    1. 什么是包

      官网解释 : 包是一种通过使用‘.模块名’来组织python模块名称空间的方式 , 具体来讲 , 包就是一个包含有__ init __.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来

      • 在python3中,即使包下没有__ init __.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
      • 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
    2. 为何要使用包

      包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来
      随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性

    3. 注意事项

      • 关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
      • import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__ init __.py,导入包本质就是在导入该文件
      • 包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

    二、包的使用

    1. 示例文件

      # 此示例摘抄他人博客,挺不错的.
      glance/                   #Top-level package
      ├── __init__.py      #Initialize the glance package
      ├── api                  #Subpackage for api
      │   ├── __init__.py
      │   ├── policy.py
      │   └── versions.py
      ├── cmd                #Subpackage for cmd
      │   ├── __init__.py
      │   └── manage.py
      └── db                  #Subpackage for db
          ├── __init__.py
          └── models.py
      
    2. 文件内容

      #文件内容
      #policy.py
      def get():
          print('from policy.py')
      #versions.py
      def create_resource(conf):
          print('from version.py: ',conf)
      #manage.py
      def main():
          print('from manage.py')
      #models.py
      def register_models(engine):
          print('from models.py: ',engine)
      # 执行文件与示范文件在同级目录下
      
    3. 包的使用(import)

      • import glance.db.models
      • glance.db.models.register_models('mysql')

      单独导入包名称时不会导入包中所有包含的所有子模块,如

      #在与glance同级的test.py中
      import glance
      glance.cmd.manage.main()
      '''
      执行结果:
      AttributeError: module 'glance' has no attribute 'cmd'
      
      ''' 
      

      解决方法:

      1 #glance/__init__.py
      2 from . import cmd
      3 #glance/cmd/__init__.py
      4 from . import manage
      

      执行:

      1 #在于glance同级的test.py中
      2 import glance
      3 glance.cmd.manage.main()
      
    4. 包的使用(from...import...)

      需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,

      如:from a import b.c是错误语法

      1 from glance.db import models
      2 models.register_models('mysql')
      3 from glance.db.models import register_models
      4 register_models('mysql')
      
    5. from glance.api import *

      此处我们研究从一个包导入所有 *,是想从包api中导入所有,实际上该语句只会导入包api下__ init __ .py文件中定义的名字,我们可以在这个文件中定义__ all ___

      #在__init__.py中定义
      x=10
      def func():
          print('from api.__init.py')
      __all__=['x','func','policy']
      

      此时我们在于glance同级的文件中执行from glance.api import *就导入__ all __中的内容(versions仍然不能导入)。

    三、绝对导入相对导入

    我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:

    1. 绝对导入:以glance作为起始
    2. 相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)

    例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py

    1 在glance/api/version.py
    2 #绝对导入
    3 from glance.cmd import manage
    4 manage.main()
    5 #相对导入
    6 from ..cmd import manage
    7 manage.main()
    

    测试结果:注意一定要在于glance同级的文件中测试

    包以及包所包含的模块都是用来被导入的,而不是被直接执行的。而环境变量都是以执行文件为准的

    绝对导入与相对导入总结

    绝对导入与相对导入
    
    绝对导入: 以执行文件的sys.path为起始点开始导入,称之为绝对导入
           优点: 执行文件与被导入的模块中都可以使用
           缺点: 所有导入都是以sys.path为起始点,导入麻烦
    
    相对导入: 参照当前所在文件的文件夹为起始开始查找,称之为相对导入
           符号: .代表当前所在文件的文件加,..代表上一级文件夹,...代表上一级的上一级文件夹
           优点: 导入更加简单
           缺点: 只能在导入包中的模块时才能使用
    注意:
     1. 相对导入只能用于包内部模块之间的相互导入,导入者与被导入者都必须存在于一个包内
     2. attempted relative import beyond top-level package # 试图在顶级包之外使用相对导入是错误的,言外之意,必须在顶级包内使用相对导入,每增加一个.代表跳到上一级文件夹,而上一级不应该超出顶级包
    

    四、logging模块(日志)

    工作日志分四个大类

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

    日志开发者使用的三个版本

    1. 简易版

      # 日志应用
      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") # 严重错误信息
      # 应用1
      def func():
          print("in func")
          logging.debug("正常执行")
      func()
      # 应用2
      try:
          i=input("请输入选项:")
          int(i)
      except Exception as e:
          logging.error(e)
      print(11)
      
      # low版的日志缺点 : 文件与屏幕同时输入只能选择一个进行
      import logging
      logging.basicConfig(
          level=10,
          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
      
    2. 标准版

      import logging
      # 创建对象
      logger=logging.getLogger() # 创建一个logging对象
      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)
      
      # 将配置好的文件格式和屏幕格式导入logging对象中
      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
      
    3. 高端版(Django项目)

      • 优点 : 自定制(通过字典的方式)日志
      • 轮转日志的功能
      # 日志旗舰版
      # 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' # 简单版
      id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 极简版
      
      # 定义日志输出格式 结束
      logfile_dir = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
      logfile_name = 'log1.log'  # log文件名,当确认功能后可以更改文件名字
      logfile_path=r"D:PyCharmpython学习day1日志学习旗舰版日志文件夹log1.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第一层所有的键都不能改变
      LOGGING_DIC = {
          'version': 1, # 版本号
          'disable_existing_loggers': False, # 固定写法
          'formatters': {
              'standard': {
                  'format': standard_format
              },
              'simple': {
                  'format': simple_format
              },
          },
          'filters': {}, # 项目用过滤
          'handlers': {
              #打印到终端的日志
              'sh': {
                  'level': 'DEBUG',
                  'class': 'logging.StreamHandler',  # 打印到屏幕
                  'formatter': 'simple'
              },
              #打印到文件的日志,收集info及以上的日志
              'fh': {
                  'level': 'DEBUG',
                  'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,轮转文件
                  'formatter': 'standard',
                  'filename': logfile_path,  # 日志文件
                  'maxBytes': 1024*1024*5,  # 日志大小 5M
                  'backupCount': 5, # 轮转文件设置为5个
                  'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
              },
          },
          'loggers': {
              #logging.getLogger(__name__)拿到的logger配置
              '': {
                  'handlers': ['sh', 'fh'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                  'level': 'DEBUG',
                  'propagate': True,  # 向上(更高level的logger)传递
              },
          },
      }
      
      dic={"username":"张三丰"}
      
      def md_logger(a):
          logging.config.dictConfig(LOGGING_DIC)  # 导入上面定义的logging配置
          logger = logging.getLogger(a)  # 生成一个log实例,()内用来区分业务
          return logger
      
      def login():
          md_logger("xx账户").debug(f'{dic["username"]}登录成功')
      
      login()
      
  • 相关阅读:
    JavaScript中的事件循环
    CSS布局
    Tomcat相关
    C#参数中ref和out的区别
    angular启动4200端口后,如何停止监听4200端口
    表联接(交叉连接,内联,外联)
    如何使用vs自带的反编译工具Lldasm
    软件架构需要注意的几点,待补充。。。
    SqlServer中With(NOLOCK)
    TypeScript preview
  • 原文地址:https://www.cnblogs.com/chenshuo531702820/p/11116937.html
Copyright © 2011-2022 走看看