道一站 道一站
首页
  • 历史文明
  • 自我管理
  • 经济金融
  • 未来科技
  • 李笑来
  • 股票
  • 期货
  • 期权
  • 外盘
  • 量化
  • 区块
  • 认知
  • 数理
  • 收藏
  • 前端

    • JavaScript
    • TypeScript
  • 页面

    • HTML
    • CSS
  • 编程

    • C++
    • Python
    • Shell
    • 小程序开发
  • 笔记

    • 《Git》
    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
  • 技术文档
  • Linux
  • Docker
  • GitHub
  • 博客搭建
  • 效用工具
  • 周易基础
  • 奇门遁甲
  • 收藏资源
  • 学习方法
  • 实用技巧
  • 友情链接
  • 分类
  • 标签
  • 归档
关于

daotoyi

静水流深
首页
  • 历史文明
  • 自我管理
  • 经济金融
  • 未来科技
  • 李笑来
  • 股票
  • 期货
  • 期权
  • 外盘
  • 量化
  • 区块
  • 认知
  • 数理
  • 收藏
  • 前端

    • JavaScript
    • TypeScript
  • 页面

    • HTML
    • CSS
  • 编程

    • C++
    • Python
    • Shell
    • 小程序开发
  • 笔记

    • 《Git》
    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
  • 技术文档
  • Linux
  • Docker
  • GitHub
  • 博客搭建
  • 效用工具
  • 周易基础
  • 奇门遁甲
  • 收藏资源
  • 学习方法
  • 实用技巧
  • 友情链接
  • 分类
  • 标签
  • 归档
关于
  • C++

  • JavaScript

  • TypeScript

  • CSS

  • HTML

  • Python

    • Python 速查表
    • python 命名规则
    • Python 相关文件常见的后缀名
    • Python 中最常用的 5 种线程
    • Python 数据规范化(归一化)及Z-score标准化
    • Python 中的绝对导入和相对导入
    • Python 中有 3 个不可思议的返回功能
    • Python 技巧分享
    • PyQt5学习资料
    • PyQt5
    • PyQt5 QDockWidget
    • Python @1装饰器入门教程!
    • Python @函数装饰器及用法
      • 带参数的函数装饰器
      • 函数装饰器可以嵌套
    • Python f-string 格式化字符串的 7 个层级
    • Python 中最常用的 5 种线程
    • Python 中有 3 个不可思议的返回功能
    • Python string去除(中文、英文、数字、标点符号)
  • Shell

  • Notes

  • 编程
  • Python
daotoyi
2023-10-07
目录

Python @函数装饰器及用法

前面章节中,我们已经讲解了 Python (opens new window) 内置的 3 种函数装饰器,分别是 @staticmethod、@classmethod 和 @property,其中 staticmethod()、classmethod() 和 property() 都是 Python 的内置函数。

那么,函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示:

def funA(fn):

    fn() 

    return '...'

@funA
def funB():
1
2
3
4
5
6
7
8

实际上,上面程序完全等价于下面的程序:

 def funA(fn):

     fn() 

     return '...'

 def funB():

  funB \= funA(funB)
1
2
3
4
5
6
7
8
9

通过比对以上 2 段程序不难发现,使用函数装饰器 A() 去装饰另一个函数 B(),其底层执行了如下 2 步操作:

  1. 将 B 作为参数传给 A() 函数;
  2. 将 A() 函数执行完成的返回值反馈回  B。

举个实例:

 def funA(fn):
     print("C语言中文网")
     fn() 
     print("http://c.biancheng.net")
     return "装饰器函数的返回值"

 @funA
 def funB():
      print("学习 Python")
1
2
3
4
5
6
7
8
9

程序执行流程为:

C语言中文网
学习 Python
http://c.biancheng.net

在此基础上,如果在程序末尾添加如下语句: print(funB)

其输出结果为:

装饰器函数的返回值

显然,被“@函数”修饰的函数不再是原来的函数,而是被替换成一个新的东西(取决于装饰器的返回值),即 ==如果装饰器函数的返回值为普通变量,那么被修饰的函数名就变成了变量名==; ==如果装饰器返回的是一个函数的名称,那么被修饰的函数名依然表示一个函数==。

实际上,所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。

# 带参数的函数装饰器

在分析 funA() 函数装饰器和 funB() 函数的关系时,细心的读者可能会发现一个问题,即当 funB() 函数无参数时,可以直接将 funB 作为 funA() 的参数传入。但是,如果被修饰的函数本身带有参数,那应该如何传值呢?

比较简单的解决方法就是在函数装饰器中嵌套一个函数,该函数带有的参数个数和被装饰器修饰的函数相同。例如:

def funA(fn):

    def say(arc):
        print("Python教程:",arc)
    return say

@funA
def funB(arc):
    print("funB():", a)
 funB("http://c.biancheng.net/python")
1
2
3
4
5
6
7
8
9
10

程序执行结果为:

Python教程: http://c.biancheng.net/python

这里有必要给读者分析一下这个程序,其实,它和如下程序是等价的:

def funA(fn):

   def say(arc):
       print("Python教程:",arc)
   return say

def funB(arc):
   print("funB():", a)

funB \= funA(funB)
funB("http://c.biancheng.net/python")
1
2
3
4
5
6
7
8
9
10
11

如果运行此程序会发现,它的输出结果和上面程序相同。

显然,通过 funB() 函数被装饰器 funA() 修饰,funB 就被赋值为 say。这意味着,虽然我们在程序显式调用的是 funB() 函数,但其实执行的是装饰器嵌套的 say() 函数。

但还有一个问题需要解决,即如果当前程序中,有多个(≥ 2)函数被同一个装饰器函数修饰,这些函数带有的参数个数并不相等,怎么办呢?

最简单的解决方式是用 *args 和 **kwargs 作为装饰器内部嵌套函数的参数,*args 和 **kwargs 表示接受任意数量和类型的参数。举个例子:

 def funA(fn):

     def say(\*args,\*\*kwargs):
         fn(\*args,\*\*kwargs)
     return say

 @funA
 def funB(arc):
     print("C语言中文网:",arc)

  @funA
  def other\_funB(name,arc):
      print(name,arc)
  funB("http://c.biancheng.net")
  other\_funB("Python教程:","http://c.biancheng.net/python")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

运行结果为:


C语言中文网: http://c.biancheng.net
Python教程: http://c.biancheng.net/python

# 函数装饰器可以嵌套

上面示例中,都是使用一个装饰器的情况,但实际上,Python 也支持多个装饰器,比如:

 @funA
 @funB
 @funC
 def fun():
1
2
3
4

上面程序的执行顺序是里到外,所以它等效于下面这行代码:

fun = funA( funB ( funC (fun) ) )

上次更新: 2023/10/10, 14:48:21
Python @1装饰器入门教程!
Python f-string 格式化字符串的 7 个层级

← Python @1装饰器入门教程! Python f-string 格式化字符串的 7 个层级→

最近更新
01
置身事内
10-10
02
基础知识|八卦五行天干地支
10-08
03
基础知识|推算年月日时的干支
10-08
更多文章>
Theme by Vdoing | Copyright © 2021-2023 Daotoyi | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式