作者:糯米不开花ぴ

python进阶 -- 日志&装饰器详解

日志

日志:记录程序运行的时候,出现的问题,或者说验证流程是否正常
在实际工作中,python的脚本命令一般是放在服务器执行的linux系统
日志其实就是记录程序运行时出现的问题、或者正常的打印,协助出现问题的时解决排查问题

python中内置的日志模块可以直接导入:

import logging

日志模块:会有日志的级别设置
级别是自己设置的,可以通过自定义的级别去确定什么东西该被记录,什么东西部该被记录

注意:设置日志级别的时候,单词全部需要大写

● DEBUG:等级最高,包含debug、info、warning、error的4种全部日志
● INFO:不包含debug日志
● WARING:不包含debug、info日志
● ERROR:不包含debug、info、warning日志
如果需要调整日志级别,level=logging.后面修改即可 

简单使用示例

import logging

logging.basicConfig(level=logging.INFO) #设置日志的打印级别

def fun1():
    logging.debug("debug打印")
    logging.info("info打印")
    logging.warning("warning打印")
    logging.error("error打印")
fun1()

 通常,在写代码的时候,我们会将一段段的代码执行结果加上日志的输出,方便在本地查看代码是否执行成功

例如:现在有一段业务逻辑代码,在执行这段代码的同时加上日志的输出

import logging

logging.basicConfig(level=logging.INFO) #设置日志的打印级别

def fun1():
    logging.debug("debug打印")
    logging.info("info打印")
    logging.warning("warning打印")
    logging.error("error打印")
#fun1()


def fun2(func_name):
    func_name()  #调用传入的函数本体
    print("这是fun2函数的调用")

fun2(fun1)

方式1:代码如上,在fun2函数调用时,括号内加上fun1这个函数名即可 

方式2:
fun2的输出内容中,fun2的原本内容与fun1的内容没有先后顺序,是并行的

所以也可以写成:最后调用时,函数1(函数3),如下:

import logging

logging.basicConfig(level=logging.INFO) #设置日志的打印级别


def log_info(fun_name):
    logging.info("日志开始记录")
    fun_name()
    logging.info("函数执行结束")

def fun3():
    print("fun3代码执行")

log_info(fun3)

方式3:用一个变量接收,然后调用新的变量名

import logging

logging.basicConfig(level=logging.INFO) #设置日志的打印级别

def log(fun_name):
    def wrapper():
        logging.info("日志开始记录")
    return wrapper  #不加括号,只是获取了wrapper这个函数的内存地址

def fun4():
    print("fun5函数执行")

method = log(fun_name=fun4)
method()  #但输出只完成了一半,并没有输出fun4的内容打印

装饰器

装饰器是Python中一种强大的编程工具,它可以用于修改、包装或扩展函数或方法的行为。装饰器本质上是一个函数,它接受一个函数作为输入,并返回一个新的函数或修改后的函数。装饰器通常用于在不修改原始函数代码的情况下,为函数添加额外的功能。

作用:

  1. 代码复用:装饰器可以用来封装通用的功能,例如日志记录、性能分析、权限检查等,以便在多个函数中重复使用。
  2. 代码修改:装饰器可以在不修改原始函数代码的情况下,对函数的行为进行修改,例如添加新的前置或后置处理逻辑。
  3. 元编程:装饰器本身是元编程的一种形式,它允许在运行时动态地修改函数或方法的行为。

装饰器的使用

接着上面的栗子,看看加上装饰器之后的代码: 

步骤:在fun5的头部加一个@函数名称,函数名称即装饰器的函数名称
在自动化的框架里面,有很多装饰器的应用,以及可以自定义装饰器去完成调用
import logging

logging.basicConfig(level=logging.INFO) #设置日志的打印级别


    def wrapper():
        logging.info("日志开始记录")
        fun()
    return wrapper  #不加括号,只是获取了wrapper这个函数的内存地址

@log   #默认会把fun5的函数本体,传入到装饰器的参数里去
def fun5():
    print("fun5函数执行")

fun5()

函数与装饰器一对多使用

一个函数是否可以使用多个装饰器?

一个函数使用了多个装饰器,执行的顺序是什么?

一起来看个案例:

def fun1(fun1_name):
    def fun2():
        print("fun1装饰器调用")
        fun1_name()
    return fun2


def fun2(fun2_name):
    def fun3():
        print("fun2装饰器调用")
        fun2_name()
    return fun3

@fun2
@fun1
def fun4():
    print("fun4函数调用")

fun4()

所以:

一个函数,可以使用多个装饰器

如果一个函数使用了多个装饰器,执行顺序,是按照装饰器的顺序,从上往下执行的