1.前言

装饰器是Python的特有的语法,刚接触装饰器的同学可能会觉得装饰器很难理解,装饰器的功能也可以不用装饰器实现,但是装饰器无疑是提高你Python代码质量的利器(尤其是使用在一些具有重复功能的场景),是Python程序员的必备技能.下面我将由浅入深的讲解装饰器语法.在学习装饰器前请记住一点.

装饰器的本质就是函数

2.Python函数

既然装饰器是函数,那我们就先从函数说起

Python中的函数很简单,比如:

def add(a, b):
return a+b

这就是一个标准的函数,有形参有返回值,知道这么多就够了!

3.在函数里面定义函数

Python的语法很自由,这使我们可以在函数里面定义一个函数.举个例子:

def func():
def inFunc():
print("---我在里面---")

当然这么写那么里面的函数就永远不会被执行.如何让里面的函数执行呢?有两种方法,我相信聪明的你们都已经猜到了!

1.在函数里面调用函数里面定义的函数,请看例子:

def func():
def inFunc():
print("---我在里面---")
inFunc()

这样子当我们在调用func()函数时,就实现了两步:

  1. 定义了一个函数inFunc()
  2. 调用了刚刚定义的函数

这样就可以执行内部函数了

2.第二种方法就是将内部函数返回给外部变量,用外部变量调用

4.返回一个函数

def func():
def inFunc():
print("---我在里面---")
return inFunc f = func() if __name__ == '__main__':
f()

注意返回时不要在函数名后面加(),因为加上()代表执行这个函数的意思.

上面的代码运行到f = func()时因为func后面加了()就回去执行func函数,func函数先会定义一个inFunc函数,然后没有执行就把刚定义的函数返回,变量f接收了func返回的函数,f()就执行了刚刚接收的函数,即inFunc函数

5.函数作为参数

既然函数里面可以定义函数,函数又可以返回函数,那么函数的参数也可以是函数吗?答案是肯定的,看个例子:

def func():
print("---我是函数func---") def otherFunc(f):
f() if __name__ == '__main__':
otherFunc(func)

这个例子很简单,你们可以自己理一下,这里就不在解释了,这个例子只是为了说明Python中函数的参数是可以为函数的.

6.把上面的组合起来

其实我们认为高大上的装饰器就是把我上面所说的拼在一个函数里就是装饰器了.

如下所示:

def myDecorator(func):  # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---") return inMyDecorator # 返回内部定义的函数

那我们要怎么调用它呢,按照之前的逻辑先要定义一个函数作为上面那个函数的参数吧(其实这就是被装饰的函数)这里定义一个函数myFunc如下

def myFunc():
print("---这是我的函数---")

然后呢?总要用一个变量来接收上面那个函数吧,接收完后总要调用吧.那么总的代码如下:

def myDecorator(func):  # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---") return inMyDecorator # 返回内部函数 def myFunc():
print("---这是我的函数---") f = myDecorator(myFunc) if __name__ == '__main__':
f()

输出:

---这是我的函数---
---我就加了一丢丢新功能---

看!这是不是有点像装饰器的样子了呢!但总感觉有什么不像(装饰器可没有变量f),那好吧,把f换成myFunc就好了吧(虽然他是之前函数名,但我们是可以改变他指向的内存空间的,一句话:用过的名字还是可以再被利用的)

再看:

def myDecorator(func):  # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---") return inMyDecorator # 返回内部函数 def myFunc():
print("---这是我的函数---") myFunc = myDecorator(myFunc) if __name__ == '__main__':
myFunc()

输出:

---这是我的函数---
---我就加了一丢丢新功能---

这下看着舒服多了.

解释一下上面代码的执行过程:

  1. 定义了函数myDecorator(实际上就是装饰器)
  2. 定义了函数myFunc(实际上就是被装饰的函数)
  3. 执行到myFunc = myDecorator(myFunc)
    1. 这里转去执行myDecorator函数,并把myFunc作为参数传给myDecorator函数
    2. myDecorator函数的形参func接收了实参myFunc函数
    3. myDecorator函数里面定义了一个inMyDecorator函数,没有执行这个函数而是把这个函数给返回了
    4. 变量myFunc接收了myDecorator函数的返回值即inMyDecorator函数
  4. 调用myFunc函数,注意这里的myFunc函数已经不是最初定义的那个函数了,而是inMyDecorator函数
    1. 执行myFunc函数相当于执行inMyDecorator函数
    2. inMyDecorator函数内先调用了 func,这个func就是第2步定义的函数
      1. 转去执行第2步定义的函数,即打印"---这是我的函数---"
    3. 执行到print("---我就加了一丢丢新功能---")这句打印"---我就加了一丢丢新功能---"
  5. 结束

7.使用@符号

其实Python中为了我们的省力把很多的步骤都用一个@符号代替掉了

看一个装饰器的官方写法(使用@符号):

def myDecorator(func):  # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---") return inMyDecorator # 返回内部函数 @myDecorator
def myFunc():
print("---这是我的函数---") if __name__ == '__main__':
myFunc()

其实这段代码的功能和之前的写法是一模一样的.

@myDecorator
def myFunc():
print("---这是我的函数---")

等价于

def myFunc():
print("---这是我的函数---") myFunc = myDecorator(myFunc)

8.被装饰的函数带参数

之前写的函数例子都是不带参数的,但是实际上带参数的函数更为常见,那如何向函数传参数呢?仔细想想,myFunc函数在被装饰后就是inMyDecorator函数.那么只要想办法步参数传给inMyDecorator函数不就行了嘛

代码稍作修改(就改了两处):

def myDecorator(func):  # 函数参数
def inMyDecorator(*args, **kwargs): # 定义内部函数
func(*args, **kwargs) # 调用参数传进来的函数
print("---我就加了一丢丢新功能---") return inMyDecorator # 返回内部函数 def myFunc(a):
print("---这是我的函数参数:{}---".format(a)) myFunc = myDecorator(myFunc) if __name__ == '__main__':
myFunc("kainhuck")

输出:

---这是我的函数参数:kainhuck---
---我就加了一丢丢新功能---

8.没想到你坚持看到了这里

希望看完这篇文章后你能写一个自己的装饰器,后续我会继续更新,装饰器带参数,和用类写一个装饰器.觉得有帮助请点个推荐吧.

往期精彩:提升Python编程效率的几种方法

深入浅出Python装饰器的更多相关文章

  1. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

  2. python装饰器通俗易懂的解释!

    1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...

  3. Python 装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...

  4. python 装饰器修改调整函数参数

    简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...

  5. python 装饰器学习(decorator)

    最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...

  6. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  7. 关于python装饰器(Decorators)最底层理解的一句话

    一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...

  8. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  9. Python装饰器与面向切面编程

    今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...

随机推荐

  1. Tensorflow官方文档 input_data.py 下载

    说明: 本篇文章适用于MNIST教程下载数据集. # Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Ap ...

  2. Linux之关于用户的几个重要配置文件

    . /etc/skel/ 用来存放新用户配置文件(环境变量)的目录,当创建新用户时,系统会把当下目录的所有文件拷贝一份到新用户家目录中,即:cp -a /etc/skel/* /home/ddu 2. ...

  3. springboot的maven多模块项目架构微服务搭建——依赖方式的多模块演化为微服务项目

    在上一篇依赖方式多模块的基础上对项目进行改造.主要改造user-service项目,service要配置mapper.mybatis及数据库相关的东西,后面的接口消费方user就不再需要了 注意:以下 ...

  4. Concurrent包下用过哪些类?

    1.executor接口,使用executor接口的子接口ExecutorService用来创建线程池2.Lock接口下的ReentrantLock类,实现同步,比如三个线程循环打印ABCABCABC ...

  5. 编译安装常用包+阿里镜像源-常用资源-系统-下载-科莱软件下载-docker仓库包-安全圈-杏雨梨云-图形界面安装-docker私有双仓库-阿里源报错处理-centos7目录大小

    yum install apr-util apr-util-devel apr apr-devel pcre pcre-devel zlib zlib-devel openssl openssl-de ...

  6. 字符设备驱动之LED驱动

    实现 ①编写驱动框架 ②编写硬件实现代码 (在Linux系统下操作硬件,需要操作虚拟地址,因此需要先把物理地址转换为虚拟地址 ioremap()) 如何实现单个灯的操作: 实现方法之一--操作次设备号 ...

  7. Unity 脚本中的update,fixedupdate,lateupdate

    先放着 有功儿夫再来整理 https://www.cnblogs.com/fly-100/p/3777731.html https://www.cnblogs.com/hont/p/5184802.h ...

  8. 【剑指Offer】面试题32 - II. 从上到下打印二叉树 II

    题目 从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行. 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回 ...

  9. UVA - 10817 Headmaster's Headache (状压dp+记忆化搜索)

    题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所 ...

  10. 中文文本分类之TextRNN

    RNN模型由于具有短期记忆功能,因此天然就比较适合处理自然语言等序列问题,尤其是引入门控机制后,能够解决长期依赖问题,捕获输入样本之间的长距离联系.本文的模型是堆叠两层的LSTM和GRU模型,模型的结 ...