• day15-包和logging模块的使用


    昨天我们讲述了模块的使用,我们知道了模块就是一个功能的集合体,讲的通俗一点,模块就是一个文件.既然我们功能多了,知道给功能根据属性放到不同的模块中,那么当我们的模块越来越多时呢?

    我们在windows图像界面文件多了的时候,我们都知道用一个文件夹去将这些文件区分,那么在python中去包含模块的文件夹呢?这个文件夹就就叫做包

    在讲包之前,我们来分析一下,文件的俩种用途??

    文件的俩种用途

    从我们昨天学的模块中,我们发现文件可以被直接执行,也可以被当作一个模块被导入到执行文件中?

    那么现在我有一个要求? 如何区分一个文件是执行文件还是被导入的模块?或者说如何实现我这个文件,当被导入时执行对应代码,当是执行文件时,又执行另外的代码?

    这时候,我们应该都会想到,欸,执行文件?那不是有一个环境变量 sys.path 和它有关吗?当是执行文件时,里面有它的直属文件夹,当是被导入时,环境变量这个列表中则没有它的直属文件夹?

    判断在没在环境变量中

    import os
    import sys
    dir = os.path.dirname(__file__)
    print(dir)  # Z:/线下培训/04-第四周/02-day02/01-区分py文件的俩种用途  这里是/ 右斜杠
    print(sys.path)  # ['Z:\线下培训\04-第四周\02-day02\01-区分py文件的俩种用途',...]  这里是左斜杠
    if dir not in sys.path:  # 因为这是在windows中,所有 我 取 反了
        s = """这是一个执行文件xxx"""
        print(s)
    else:
        y = """这是在被导入时执行的文件xxx"""
        print(y)
    

    你一看?我靠?这么麻烦?这一搞,文件内的代码,不是看起来很乱?

    其实python内置了一个 内置属性就可以做到这样,甚至有过之而不不及.

    __name__属性

    那就是 _name_, 当 __name__ 是一个被执行的文件时,它返回的值为 __main__ ,当是被当作模块导入时,返回的是它本身即模块名.

    所以我们可以这样做

    def f1():
        print('xxxxxxx')
    
    
    # print(__name__)
    
    if __name__ == '__main__':
        f1()
    

    这时,条件判断之外的为模块时执行的,条件判断之内的为执行文件时执行的

    但,一般一个项目只有一个执行文件,但是碍于好区分,可以在执行文件中加上 这个条件判断.

    下面开始介绍包

    概念:文件夹内包含一个_init_.py

    功能:将导入模块语句放到一个包内,通过改变_init_.py文件来使执行者不改变使用语法的情况下,改变了模块的位置.

    什么意思??这么抽象???

    别急,让我们来看看具体实例

    包的由来以及实例

    本来所有的模块和功能都来自一个模块中,即使用者的使用方法为:aaa.功能名

    但为了解决设计者的维护困难,因此设计者将其分成了下面的目录结构.

    要求,不改变使用方法,原使用方法为 aaa.f1(),aaa.f2(),aaa.f3().

    目录结构为:

    包的使用  (这是一个文件夹) 
    	- aaa
    		- __init__py  (为aaa下的包)
    		- bbb
    			- __init__.py  (为bbb下的包)
    			- m3.py  (为bbb这个文件夹下的模块)
    		- m1.py  (为aaa这个文件夹下的模块)
    		- m2.py  (为aaa这个文件夹下的模块) 
    	- run.py  (为执行文件)
    

    其中 m1 模块下.有一个功能 叫做 f1. m2 模块下也有一个功能叫做 f2 ,m3 模块中 也有一个功能 叫做 f3

    即m1,m2,m3的文件内容为

    # m1.py
    def f1():
        print('m1.f1')
    
    # m2.py
    def f2():
        print('m2.f2')
    
    # m3.py
    def f3():
        print('m3.f3')
    

    问,我如何可以使用到f1,f2,f3这些功能

    方案1:昨天的模块

    # run.py文件
    from aaa import m1,m2
    from aaa.bbb import m3
    
    m1.f1()
    m2.f2()
    m3.f3()
    

    但是这样做并没有解决,使用方法不改变的情况.我们就想实现,用aaa.f1(),aaa.f2(),aaa.f3().

    所以这时候我们就可以使用包的一些特性,那就是包的_init_.py文件了

    方案2:包来解决

    # aaa下的__init__.py文件
    from .m1 import f1
    from .m2 import f2
    from .bbb.m3 import f3
    
    # run.py的文件
    import aaa
    
    aaa.f1()
    aaa.f2()
    aaa.f3()
    

    欸,这就满足了,我使用者没改变使用方法,而,设计者又分成了若干个包,利于维护的需求.

    其实以上就是包的由来

    仔细的同学,你可能会发现我们在aaa的__init__.py文件中在导入语句中使用了 .这个 字符?

    是的,当我们在包内使用导入语句可以使用 ...,以及...,......, 那 它们代表的都是什么意思呢?

    其实在包的导入中.表示的就是当前的文件夹 即这里的 . 表示的就是 aaa这个文件夹,..表示的就是上一级的文件夹,...表示的是上上上一级的文件夹 ....,依次类推.但是,它们有一个大前提,那就是必须在包内使用,而且 不能超出 包的范围. 即 就是该包的最顶级文件夹.

    总结一下包

    1、导包就是在导包下_init_.py文件
    2、包内部的导入应该使用相对导入,相对导入也只能在包内部使用,而且...取上一级不能出包
    3、
    使用语句中的点代表的是访问属性
    m.n.x ----> 向m要n,向n要x
    而导入语句中的点代表的是路径分隔符
    import a.b.c --> a/b/c,文件夹下a下有子文件夹b,文件夹b下有子文件或文件夹c
    所以导入语句中点的左边必须是一个包

    到这.我们自己自定义的功能呐,模块啊,包啊.都已经结束了,那么接下来就是一些 别人写好的 模块了.即常用模块

    logging 模块

    简介

    Python的logging模块提供了通用的日志系统,可以方便第三方模块或者是应用使用。这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP GET/POST,SMTP,Socket等,甚至可以自己实现具体的日志记录方式。

    日志级别

    CRITICAL = 50 #FATAL = CRITICAL
    ERROR = 40
    WARNING = 30 #WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0 #不设置
    

    模块提供logger,handler,filter,formatter。

    • logger:提供日志接口,供应用代码使用。logger最常用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
    • handler:将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。
    • filter:提供一种优雅的方式决定一个日志记录是否发送到handler。
    • formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。

    logger,handler和日志消息的调用可以有具体的日志级别(Level),只有在日志消息的级别大于logger和handler的级别才放行。

    logging用法解析

    1. 初始化 logger = logging.getLogger("endlesscode"),getLogger()方法后面最好加上所要日志记录的模块名字,后面的日志格式中的%(name)s 对应的是这里的模块名字
    2. 设置级别 logger.setLevel(logging.DEBUG),Logging中有NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL这几种级别,日志会记录设置级别以上的日志
    3. Handler,常用的是StreamHandler和FileHandler,windows下你可以简单理解为一个是console和文件日志,一个打印在终端的窗口上,一个记录在一个文件上
    4. formatter,定义了最终log信息的顺序,结构和内容
      %(name)s Logger的名字
      %(levelname)s 文本形式的日志级别
      %(message)s 用户输出的消息
      %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
      %(levelno)s 数字形式的日志级别
      %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
      %(filename)s 调用日志输出函数的模块的文件名
      %(module)s 调用日志输出函数的模块名
      %(funcName)s 调用日志输出函数的函数名
      %(lineno)d 调用日志输出函数的语句所在的代码行
      %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
      %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
      %(thread)d 线程ID。可能没有
      %(threadName)s 线程名。可能没有
      %(process)d 进程ID。可能没有
    5. 记录 使用object.debug(message)来记录日志

    介绍来自互联网

    我直接上实例吧!让我们写出我们的第一个记日志的小功能

    # -*- coding: utf-8 -*-
    # @Author  : JKey  
    # Timer    : 2021/1/5 14:15
    import logging
    
    # 创建一个logger对象
    logger = logging.getLogger('my_logger')
    logger.setLevel(logging.DEBUG)
    
    # 创建一个handler.用于写入日志文件
    fh = logging.FileHandler("test.log")
    fh.encoding = 'utf-8'
    fh.setLevel(logging.DEBUG)
    
    # 再创建一个handler,用于输出到控制台
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    
    # 定义handler的输出格式
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    
    # 给logger添加handler
    logger.addHandler(fh)
    logger.addHandler(ch)
    
    logger.info('你好啊,第一个log信息')
    

    放入到我们之前写的项目中,即

    - conf
    	- settings.py
        	# 文件内容
            # -*- coding: utf-8 -*-
            # @Author  : JKey
            # Timer    : 2021/1/5 12:19
            import os
    
            FUNC_DICT = {}
            BASE_DIR = os.path.dirname(os.path.dirname(__file__))
            A1_LOG = f'{BASE_DIR}/log/a1.log'
            A2_LOG = f'{BASE_DIR}/log/a2.log'
    
            standard_format = '%(asctime)s %(filename)s:%(lineno)d %(name)s %(levelname)s %(message)s'
            simple_format = '%(asctime)s %(message)s'
            LOGGING_DIC = {
                'version': 1,
                'disable_existing_loggers': False,
                'formatters': {
                    'standard': {
                        'format': standard_format
                    },
                    'simple': {
                        'format': simple_format
                    },
                },
                'filters': {},
                'handlers': {
                    #打印到文件的日志,收集info及以上的日志
                    'file1': {
                        'level': 'DEBUG',
                        'class': 'logging.FileHandler',  # 保存到文件
                        'formatter': 'standard',
                        'filename': A1_LOG,
                        'encoding': 'utf-8',
                    },
                    'file2': {
                        'level': 'DEBUG',
                        'class': 'logging.FileHandler',  # 保存到文件
                        'formatter': 'standard',
                        'filename': A2_LOG,
                        'encoding': 'utf-8',
                    },
                    #打印到终端的日志
                    'stream': {
                        'level': 'DEBUG',
                        'class': 'logging.StreamHandler',  # 打印到屏幕
                        'formatter': 'simple'
                    },
                },
                'loggers': {
                    #logging.getLogger(__name__)拿到的logger配置
                    # 其中''表示的是默认的,即不管什么名称,只要没匹配上,其他的key,就都使用该''key里面的配置
                    '': {
                        'handlers': ['file1','file2','stream'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                        'level': 'ERROR',  # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                        'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
                    },
                    '提示日志': {
                        'handlers': ['stream'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                        'level': 'ERROR',  # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                        'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
                    },
                },
            }
    
    - core
    	- src.py
            # -*- coding: utf-8 -*-
            # @Author  : JKey
            # Timer    : 2021/1/5 8:51
            from lib import common
            from conf import settings
    
    
            @common.add_dic(1, "注册")
            def register():
                """注册"""
                print('注册中')
    
    
            @common.add_dic(2, "登录")
            def login():
                """登录"""
                print('登陆')
    
    
            @common.add_dic(3, "取款")
            def withdraw():
                """取款"""
                print('取款')
                logger1 = common.get_logger("用户交易")
                logger1.error("lxx取了1个亿")
    
    
            @common.add_dic(4, "转账")
            def transfer():
                """转账"""
                print('转账')
    
    
            def run():
                while True:
                    for k, v in settings.FUNC_DICT.items():
                        print(k, v[0])
    
                    chios = input('请输入你的选择>>>:').strip()
                    if chios in settings.FUNC_DICT:
                        settings.FUNC_DICT[chios][1]()
                    else:
                        print('error')
    
    - lib
    	- common.py
        	# -*- coding: utf-8 -*-
            # @Author  : JKey
            # Timer    : 2021/1/5 8:51
            from lib import common
            from conf import settings
    
    
            @common.add_dic(1, "注册")
            def register():
                """注册"""
                print('注册中')
    
    
            @common.add_dic(2, "登录")
            def login():
                """登录"""
                print('登陆')
    
    
            @common.add_dic(3, "取款")
            def withdraw():
                """取款"""
                print('取款')
                logger1 = common.get_logger("用户交易")
                logger1.error("lxx取了1个亿")
    
    
            @common.add_dic(4, "转账")
            def transfer():
                """转账"""
                print('转账')
    
    
            def run():
                while True:
                    for k, v in settings.FUNC_DICT.items():
                        print(k, v[0])
    
                    chios = input('请输入你的选择>>>:').strip()
                    if chios in settings.FUNC_DICT:
                        settings.FUNC_DICT[chios][1]()
                    else:
                        print('error')
    
    - log
    	- a1.log
        - a2.log
    -start.py
    	# -*- coding: utf-8 -*-
        # @Author  : JKey  
        # Timer    : 2021/1/5 14:25
    
    
        from core import src
    
    
        if __name__ == '__main__':
            src.run()
    

    其中的 settings中的日志字典LOGGING_DIC是本模块的重点.建议,copy到pycharm中进行,分析.其实也就是针对了 logging 模块内的 logger,handle, 和 formatter,以及filter 这几个 对象进行 配置以及 搭配即可.

    总结:

    1.文件的俩种类型

    • 1.1:文件为被执行文件

    • 1.2:文件为被导入文件,即模块

    • 有一个内置方法__name__,被执行时返回__mian__,被当作模块导入时返回模块名

    • 可以得到一个条件判断语句

      if __name__ == '__main__':
         	pass
      

    2.包的介绍

    • 2.1包其实就是一个文件夹,内置有__init__.py的.
    • ps:在python2中这个py文件必须要有,在python3中可以没有

    3.包的使用

    • 3.1:导入包其实就是相当于导入包内的__init__.py文件

    4.使用包的注意事项

    • 4.1:使用相对导入时,不能超过包的范围

    5.logging 模块的 使用

    • 5.1:这里,只需要你掌握怎么使用即可,即把那个LOGGING_DIC研究怎么改里面的key和属性即可
  • 相关阅读:
    青春三部曲(《且听风吟》,《一九七三年的弹子球》,《寻羊冒险记》)--[日]村上春树
    《假如给我三天光明》--[美]海伦·凯勒
    《老人与海》--[美]欧内斯特·米勒尔·海明威
    《曾国藩发迹史》--汪衍振
    《挪威的森林》--[日]村上春树
    《海边的卡夫卡》--[日]村上春树
    你也可以用java的swing可以做出这么炫的mp3播放器_源码下载
    你用java的swing可以做出这么炫的mp3播放器吗?
    《罗密欧与朱丽叶》--[英]莎士比亚
    《肖申克的救赎》--[美]斯蒂芬·金
  • 原文地址:https://www.cnblogs.com/jkeykey/p/14236718.html
Copyright © 2020-2023  润新知