python装饰器代码深入讲解

作者:newname 时间:2023-08-17 20:59:19 

python装饰器就是用于扩展原函数功能的一种函数,这个函数特殊的地方就是它的返回值也是一个函数,使用Python装饰器的一个好处就是:在不需要修改原函数代码的情况下,给函数增加新的功能。

先来看个例子:


def say():
print('Nice day')

say()
# 这个函数的输出为:
Nice day

现在,我想在输出Nice day的前面再打印一行****************,类似下面的效果:

**************** 

Nice day

一般情况下,我可以修改上面的代码:


def say():
print('****************')
print('Nice day')

say()

可是,如果我忽然发现自己看错了需求,这时候又要把代码修改到原来的样子,庆幸的是我只是在原来函数的基础上增加了一行代码,想要回到原来的状态并不难,可如果我是修改了复杂的逻辑,代码有一百行呢,难道我还要一步步撤销吗?显然做不到,不过没关系,肯定还有别的办法:


def say():
print('Nice day')

def outer(): # 重新定义一个新函数
print('****************') # 处理新的逻辑
say() # 再调用原来的函数

outer()
# 现在的输出为:
'''
****************
Nice day
'''

怎么样,看上去已经满足要求了吧,不过仔细一看,就能发现新的问题,如果不仅仅是say()函数需要打印****************,新来的talk()函数也需要呢,这时候我又要再写一个outer()函数吗?这会累坏丹丹的,所以得再想个办法:


def say():
print('Nice day')

def talk():
print('I am talk')

def outer(func): # 接收一个函数
print('****************') # 处理新的逻辑
func() # 调用传递过来的函数

outer(talk) # 把talk函数作为参数传递过去
# 输出结果如下:
'''
****************
I am talk
'''

这时,不管有几个函数需要打印****************,我直接把函数名传给outer()就可以啦,是不是方便很多^-^ 但是勤劳的丹丹会止步于此吗?肯定不会,于是又把代码做了如下修改:


def say():
print('Nice day')

def outer(func):
def inner():
print('****************')
func() # 相当于 say()
return inner

s = outer(say) # 相当于 s = inner
s() # 相当于 inner()

猜猜这次的是输出是什么~当然还是和上面一样啦!其实这里只是把处理逻辑的部分封装在了一个函数里面,调用outer(say)的时候,把say传给outer,获得返回值inners,此时的s就相当于inners()也就相当于inner()所以会输出:

**************

Nice day

这就是一个最简单的装饰器啦,是不是很简单~ 但是我们每次在使用的时候还需要先赋值给一个变量(这里的s),然后再经由s调用,未免违反了丹丹“多一行代码都是累赘”的原则,所以我们再修改一下代码:


def outer(func):
def inner():
print('****************')
func()
return inner

@outer # 用outer装饰say
def say():
print('Nice day')

say() # 调用say函数

我把outersay调换了一下位置,先定义了outer函数,@outer表示用outer装饰say,这样直接用say()就能实现我想先打印一行****************的功能了,如果不调换两个函数的位置,是会报NameError: name 'outer' is not defined的错误的噢(作用域的原因,outer未定义),这个应该算是复杂一点的装饰器了吧,哈哈
这时候很多细心同学肯定就会问了,你写的都是无参的呀,那如果我的函数有参数怎么办呢,参数还是不固定的又该怎么办呢?万能的python+聪明的丹丹当然可以解决:


# 带参数的装饰器
def outer(func):
def inner(name):
func(name)
return inner

@outer
def say(name):
print('name is %s.' % (name))

say('dandan')
# name is dandan.

不过这个参数个数是固定的,万一我又突发奇想,想多传一个hobby或者age怎么办呢?


# 带不定参数的装饰器
def outer(func):
def inner(*args, **kwargs):
func(*args, **kwargs)
return inner

@outer
def say(name, age):
print('name is %s, age is %d.' % (name, age))

@outer
def talk(name, age, hobby):
print('name is %s, age is %d, hobby is %s.' % (name, age, hobby))

say('dandan', 18)
talk('dandan', 18, 'Coding')
'''
name is dandan, age is 18.
name is dandan, age is 18, hobby is Coding.
'''

如果我要新增的功能有很多,一个装饰器搞不定,怎么办呢?我可以同时使用多个装饰器吗?当然可以:


# 多个装饰器
def outer(func):
def inner(*args, **kwargs):
print('****************')
func(*args, **kwargs)
return inner

def outer2(func):
def inner2(*args, **kwargs):
print('这里有1w+新功能')
func(*args, **kwargs)
return inner2

@outer
@outer2
def say(name, age):
print('name is %s, age is %d.' % (name, age))

@outer
@outer2
def talk(name, age, hobby):
print('name is %s, age is %d, hobby is %s.' % (name, age, hobby))

say('dandan', 18)
talk('dandan', 18, 'Coding')
'''
****************
这里有1w+新功能
name is dandan, age is 18.
****************
这里有1w+新功能
name is dandan, age is 18, hobby is Coding.
'''

要注意的是,多个装饰器的执行顺序是从第一个装饰器开始,执行到最后一个装饰器,再执行函数本身。

来源:https://blog.csdn.net/qq_25046261/article/details/79558058

标签:python,装饰器
0
投稿

猜你喜欢

  • ASP内置对象Request和Response用法详解

    2007-09-14 10:35:00
  • python实现傅里叶级数展开的实现

    2022-06-14 14:35:17
  • 使用Kivy将python程序打包为apk文件

    2021-01-17 21:04:11
  • mysql遇到load data导入文件数据出现1290错误的解决方案

    2024-01-29 09:53:12
  • Python网络爬虫实例讲解

    2023-09-11 23:18:10
  • 基于Python爬取股票数据过程详解

    2021-02-27 08:42:18
  • Python3操作读写CSV文件使用包过程解析

    2022-06-04 03:27:01
  • WEB前端开发经验总结之实战篇

    2008-06-12 12:49:00
  • 代码实例讲解python3的编码问题

    2022-08-19 10:59:15
  • 表格梳理解析python内置时间模块看完就懂

    2023-10-21 08:10:27
  • 合成大西瓜开发源码手把手教你运行和部署大西瓜游戏项目(附源码)

    2023-11-01 05:39:13
  • SQL执行步骤的具体分析

    2024-01-17 15:47:54
  • 如何使用分区处理MySQL的亿级数据优化

    2024-01-21 04:49:01
  • Hello! 404

    2010-09-06 13:37:00
  • IE9一个非常牛的“bug”

    2010-05-07 12:45:00
  • Go语言实现的可读性更高的并发神库详解

    2023-07-20 08:03:49
  • asp中利用xmlhttp抓取网页内容的代码

    2023-07-06 04:18:12
  • 在ASP.NET 2.0中操作数据之三十六:在DataList里编辑和删除数据概述

    2024-05-09 09:03:43
  • 浅谈Python中的可变对象和不可变对象

    2021-07-17 16:58:49
  • js中如何对url进行编码和解码

    2023-07-22 03:45:08
  • asp之家 网络编程 m.aspxhome.com