L12-聊聊Python的装饰器

2023-05-16

文章目录

    • 1. 基本介绍
    • 2. 理解函数
      • 2.1 函数也是对象
      • 2.2 嵌套函数
      • 2.3 返回结果为函数
      • 2.4 函数作为输入参数
    • 3.创建装饰器
    • 4.带参数的装饰器
    • 5.装饰器的应用-监控日志

1. 基本介绍

  • 定义
    在函数调用前后自动打印日志,称之为“装饰器”(Decorator)

  • 本质
    decorator就是一个 返回函数的高阶函数,是返回函数的一种用途。
    将业务code与日志code解码的过程。输入的变量是一个函数:负责处理业务

  • 使用方式
    利用python语法糖 @语法

  • 核心点
    Python中,一切皆为对象,函数也不例外

2. 理解函数

2.1 函数也是对象

def hi(name="yasoob"):
    return "hi " + name
    
print(hi())
# output: 'hi yasoob'
# 我们甚至可以将一个函数赋值给一个变量,比如
greet = hi
# 我们这里没有在使用小括号,因为我们并不是在调用hi函数
# 而是在将它放在greet变量里头。我们尝试运行下这个
print(greet())
# output: 'hi yasoob'
# 如果我们删掉旧的hi函数,看看会发生什么!
del hi
print(hi())
#outputs: NameError

print(greet())
#outputs: 'hi yasoob'

2.2 嵌套函数

def hi(name="yasoob"):
    print("now you are inside the hi() function")

    def greet():
        return "now you are in the greet() function"

    def welcome():
        return "now you are in the welcome() function"

    print(greet())
    print(welcome())
    print("now you are back in the hi() function")

hi()
#output:now you are inside the hi() function
#       now you are in the greet() function
#       now you are in the welcome() function
#       now you are back in the hi() function

# 上面展示了无论何时你调用hi(), greet()和welcome()将会同时被调用。
# 然后greet()和welcome()函数在hi()函数之外是不能访问的,比如:

greet()
#outputs: NameError: name 'greet' is not defined

2.3 返回结果为函数

从函数中返回函数.其实并不需要在一个函数里去执行另一个函数,我们也可以将其作为输出返回出来

def hi(name="yasoob"):
    def greet():
        return "now you are in the greet() function"

    def welcome():
        return "now you are in the welcome() function"

    if name == "yasoob":
        return greet
    else:
        return welcome

a = hi()
print(a)
#outputs: <function greet at 0x7f2143c01500>

#上面清晰地展示了`a`现在指向到hi()函数中的greet()函数
#现在试试这个

print(a())
#outputs: now you are in the greet() function

在 if/else 语句中我们返回 greet 和 welcome,而不是 greet() 和 welcome()。为什么那样?这是因为当你把一对小括号放在后面,这个函数就会执行;然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。
再稍微多解释点细节。
当我们写下 a = hi(),hi() 会被执行,而由于 name 参数默认是 yasoob,所以函数 greet 被返回了。如果我们把语句改为 a = hi(name = “ali”),那么 welcome 函数将被返回。我们还可以打印出 hi()(),这会输出 now you are in the greet() function。

2.4 函数作为输入参数

def hi():
    return "hi yasoob!"

def doSomethingBeforeHi(func):
    print("I am doing some boring work before executing hi()")
    print(func())

doSomethingBeforeHi(hi)
#outputs:I am doing some boring work before executing hi()
#        hi yasoob!

3.创建装饰器

from functools import wraps
def a_new_decorator(a_func):
    @wraps(a_func)#
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
        a_func()
        print("I am doing some boring work after executing a_func()")
    return wrapTheFunction

def a_function_requiring_decoration():
    print("I am the function which needs some decoration to remove my foul smell")

a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()

a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
#        I am the function which needs some decoration to remove my foul smell
#        I am doing some boring work after executing a_func()

函数不需要做任何修改,只需在定义的地方加上装饰器,调用的时候还是和以前一样,如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性

4.带参数的装饰器

装饰器在 Python 使用如此方便都要归因于 Python 的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

想想这个问题,难道@wraps不也是个装饰器吗?但是,它接收一个参数,就像任何普通的函数能做的那样。那么,为什么我们不也那样做呢? 这是因为,当你使用@my_decorator语法时,你是在应用一个以单个函数作为参数的一个包裹函数。记住,Python里每个东西都是一个对象,而且这包括函数!记住了这些,我们可以编写一下能返回一个包裹函数的函数。

from functools import wraps

def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as opened_file:
                # 现在将日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator

@logit()
def myfunc1():
    pass

myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串

@logit(logfile='func2.log')
def myfunc2():
    pass

myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串

5.装饰器的应用-监控日志

from functools import wraps

def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging

@logit
def addition_func(x):
   """Do some math."""
   return x + x
   
result = addition_func(4)
# Output: addition_func was called
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

L12-聊聊Python的装饰器 的相关文章

随机推荐

  • 7-53 两个有序序列的中位数 (25 分)

    已知有两个等长的非降序序列S1 S2 设计函数求S1与S2并集的中位数 有序序列A 0 A 1 AN 1的中位数A N 1 2的值 即第 N 43 1 2 个数 xff08 A 0为第1个数 xff09 输入格式 输入分三行 第一行给出序列
  • PROC系列之---/proc/stat/

    包含了所有CPU活动的信息 xff0c 该文件中的所有值都是从系统启动开始累计到当前时刻 work 64 builder cat proc stat cpu 432661 13295 86656 422145968 171474 233 5
  • PROC系列之---/proc/pid/stat

    proc stat 包含了所有CPU活跃的信息 xff0c 该文件中的所有值都是从系统启动开始累计到当前时刻 root 64 localhost cat proc 6873 stat 6873 a out R 6723 6873 6723
  • PROC系列之---/proc/pid/statm

    proc statm 包含了所有CPU活跃的信息 xff0c 该文件中的所有值都是从系统启动开始累计到当前时刻 root 64 localhost cat proc self statm 654 57 44 0 0 334 0 输出解释 C
  • Linux下使用socket传输文件的C语言简单实现

    简单的C语言实现 xff0c 客户端通过TCP协议向服务器端请求传输的文件 xff0c 服务器端收到请求后向客户端发送文件 服务器程序和客户端程序应当分别运行在两台计算机上 在运行服务器端的计算机终端执行 xff1a file server
  • 设置linux进程优先级和CPU亲和性(转载)

    进程cpu资源分配就是指进程的优先权 xff08 priority xff09 优先权高的进程有优先执行权利 配置进程优先权对多任务环境的linux很有用 xff0c 可以改善系统性能 还可以把进程运行到指定的CPU上 xff0c 这样一来
  • 20130718:Linux内核编译

    最近在学习 操作系统概念 一书 xff0c 有些实验需要在系统内核中增加一些新的系统调用 xff0c 由此便产生了修改内核源码并重新编译生成新内核的需求 我的思路是 首先搞定内核编译的流程 xff0c 确保有个可用的实验环境 xff0c 在
  • Linux Bash Shell 学习笔记

    1 bash脚本的参数处理 BASH的参数可以用 加数字编号来访问 xff0c 其中 xff1a 代表脚本的参数个数 1代表脚本的第1个参数 2代表脚本的第2个参数 以此类推 xff0c n代表脚本的第n个参数 xff0c 但是 xff0c
  • L1-python中的特殊方法__str__

    1 使用场景 在Python的类的定义中 xff0c init 方法用来初始化实例属性 当创建类对象并打印输出时 xff0c 默认输出结果会是一串地址符 xff0c 如 xff1a lt main Student object at 0x0
  • L3-python语言中的几种特征操作

    汇总了目前碰到的几个Python有别于其它程序语言特征 xff0c 体现了Python语言自有的简洁与优雅 xff0c 可参考如下使用与注意事项 列表推导式 一行代码直接对列表元素进行翻倍操作 xff0c 比for的遍历 xff0c 简洁
  • 7-13 统计工龄 (20 分)

    给定公司N名员工的工龄 xff0c 要求按工龄增序输出每个工龄段有多少员工 输入格式 输入首先给出正整数N xff08 10 5 xff09 xff0c 即员工总人数 xff1b 随后给出N个整数 xff0c 即每个员工的工龄 xff0c
  • L4-深度分析Python数据库(SQLServer)访问中的连接

    1 环境准备 首先就是要安装包 xff0c 直接使用pip命令安装即可 pip install pymssql 2 Python pymssql库的数据库访问分析 参考下图 xff0c 描述了数据库连接在单次访问中的创建与关闭 值得注意的是
  • L5-利用Python生成器巧解算法小题

    介绍两个利用Python生成器替代传统的循环遍历操作来解决问题的例子 经过思考与实践 xff0c 充分利用这种自有特征 xff0c 理解实现的细节 xff0c 感受这种编程方式的优雅 1 字符替换 将 aeiou 进行替换 xff0c 规则
  • L6-Numpy中的随机函数

    文章目录 1 rand 2 randn 3 randint 4 random 5 choice 6 随机种子seed 本文汇总了Numpy中常见的取随机数的函数 xff0c 介绍了基本用法 1 rand 指定的输出的二维数组的型 xff0c
  • L7-Python字符串格式化小结

    文章目录 一 百分号 1 直接使用2 表达式赋值3 绑定变量名4 格式符汇总说明5 更精细化的控制 二 format控制基本语法1 绑定变量名2 绑定对象属性3 通过下标取元素来赋值4 填充与对齐5 精度与类型6 千位分隔符 本篇汇总了Py
  • L8-Flatten拍平多维数组的元素

    文章目录 案例说明1 最平凡 xff1a 数组索引访问2 最伤脑 xff1a 二次遍历 列表生成器3 最灵巧 xff1a 活用函数sum 为什么sum 还可以这样玩 xff1f 4 最省心 xff1a 一步到位 xff0c Numpy fl
  • L9-Python内部变量的作用域问题

    文章目录 写在开头一 连续等式判断二 函数内部变量作用域的变更1 对外部变量不进行运算 xff0c 直接访问2 直接对外部变量进行操作运算3 新增global声明 xff0c 再操作 写在开头 分享 记录两个有意思的案例 xff0c 平时碰
  • L10-简谈正则表达式中几个函数的使用

    文章目录 概述1 match 2 search 3 sub 4 compile 5 findall 6 finditer 7 split 8 subn 9 groups 10 贪婪模式与惰性模式注意事项 概述 正则表达式本身是一种小型的 高
  • L11-Python中的高阶函数的使用

    Python中的函数是一个对象 xff0c 既可以作为输入参数 xff0c 也可以作为返回结果 在这里聊聊几个常用的高阶函数 xff0c 来看看函数是如何被作为输入参数 返回结果来使用的 1 map 映射函数 语法 xff1a map fu
  • L12-聊聊Python的装饰器

    文章目录 1 基本介绍2 理解函数2 1 函数也是对象2 2 嵌套函数2 3 返回结果为函数2 4 函数作为输入参数 3 创建装饰器4 带参数的装饰器5 装饰器的应用 监控日志 1 基本介绍 定义 在函数调用前后自动打印日志 xff0c 称