1.装饰器的概念

  装饰器本质上就是一个函数,主要是为其他的函数添加附加的功能,装饰器的原则有以下两个:

  • 装饰器不能修改被修饰函数的源代码
  • 装饰器不能修改被修改函数的调用方式  

  装饰器可以简单的理解为:高阶函数+嵌套函数+闭包


2.高阶函数

  高阶函数我在前面的博客中已经讲过了,在这里我再简单的说一下吧。

  高阶函数:如果一个函数接收的参数是一个函数名,或者返回值是函数名,只要满足任意一个条件,这个函数就称为高阶函数。

  • 接收的参数是一个函数名
def foo():
print("the result from foo")
def bar(func):
func()
print("the result from bar")
bar(foo)

  在上面的例子中,我定义了两个函数,foo()和bar(),在调用bar()函数的时候,我将foo()作为一个参数传给了bar(),运行就会得到foo()的结果,这样的函数就可以成为高阶函数。

  • 返回值是一个函数名
def foo():
print("the result from foo")
def bar(func):
return func
bar(foo)

  调用bar()函数 返回的就是foo()的内存地址,这也可以称为高阶函数。


3.函数嵌套

  函数嵌套:函数嵌套我在前面也已经讲过了,其实就是函数的内部再声明函数,很好理解的一个概念,举个例子:如下

def foo():
print("the result from foo")
def bar():
print("the result from bar")
bar()
foo()

  在上面这个例子中,我在函数foo()的内部又写了一个bar()函数,并在下面调用了该函数,这种方式就叫做函数嵌套,可以嵌套很多层,只要注意函数缩进问题


4.闭包

  在Python中闭包的表现形式可以理解为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

  单从上面的定义可能很难理解,我下面用一个简单的程序说明一下:

def foo():
a=1
b=2
def bar():
c=3
return a+b+c
return bar
print(foo()())

  在上面这个例子中,bar()就是foo()的一个内部函数,在bar()的局部作用于可以直接使用foo()的局部变量a,b,简单的说,这种内部函数可以访问外部函数变量的行为,就叫做闭包。


4.装饰器实例

  为了能让大家更好的理解装饰器,我会分步做出这个实例。

  • 装饰器的基本实现

  先定义一个函数name(),3秒后打印名字

import time
def name():
time.sleep(2)
print("my name is 尼古拉斯赵四")
name()

  现在有一个需求,我想要统计这个函数一个运行了多少秒,在不修改源代码的情况下,就需要给这个函数写一个装饰器来完成这个需求。

def timmer(func):       #定义一个形参,就是为了接受name()这个函数,注意前面文章就已经强调过的:函数即变量---func=name
def wapper(): #定义函数wapper(),用来接收name的参数
start_time=time.time()
func() #实质上就是在运行test()
stop_time=time.time()
print("name()函数一共运行了%s 秒"%(stop_time-start_time))
return wapper import time
@timmer #使用装饰器的方法,通过@+作为装饰器的那个函数名
def name():
time.sleep(2)
print("my name is 尼古拉斯赵四")
name()
运行结果:
my name is 尼古拉斯赵四
name()函数一共运行了2.0002381801605225 秒

  上面这个例子就是一个简单的装饰器,没有修改原函数的调用方法和返回值,装饰器timmer中用到了高阶函数+函数嵌套+闭包的知识,ok,完美。

  • 在装饰器中添加参数

      上面的例子是完美的实现了所需要的功能,但是问题来了,如果原函数是现在这样呢?
def name(my_name,my_age):
time.sleep(2)
print("my name is %s,my age is %s"%(my_name,my_age))
name("尼古拉斯赵四",18)

  我需要随机传入两个值,打印出他的姓名和年龄,如果原函数这样调用,使用上面的装饰器肯定会出错,那就需要在装饰器函数中做如下修改:def wapper(my_name,my_age)func(my_name,my_age)这两行加入相同的参数,也是可以的,但如果name函数我再修改呢,不传入两个参数了 ,传3个 或更多,每次都要去修改岂不是很麻烦,这就需要做一些改变了 。

def timmer(func):
def wapper(*args,**kwargs): #这里用*args,**kwargs代替,这样 ,不管原函数传入多少个参数,都可以匹配
start_time=time.time()
func(*args,**kwargs) #同样,接受任意多个参数 (如果不懂这个什么意思,翻看我前面函数篇的博客,有讲到)
stop_time=time.time()
print("name()函数一共运行了%s 秒"%(stop_time-start_time))
return wapper

  • 装饰器添加返回值

      参数问题解决了,下面我的原函数又变了
def name(my_name,my_age):
time.sleep(2)
print("my name is %s,my age is %s"%(my_name,my_age))
return "尼古拉斯 你真年轻"
print(name("尼古拉斯赵四",18))
运行结果:
my name is 尼古拉斯赵四,my age is 18
尼古拉斯 你真年轻

  在这个函数中,我需求是在运行完函数返回"尼古拉斯 你真年轻"这句话,还是用上面的装饰器返回值会是my name is 尼古拉斯赵四,my age is 18 name()函数一共运行了2.000795364379883 秒 None,返回值是None而不是想要的结果,大家可以试一下,所以要加如下修改:

def timmer(func):
def wapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs) #将func()运行结果赋值给变量res
stop_time=time.time()
print("name()函数一共运行了%s 秒"%(stop_time-start_time))
return res #返回res,其实就是在返回name()
return wapper

  上面就详细写了装饰器的实现过程,就先写到这,后续我会丰富装饰器并做出一个通俗易懂的例子供大家参考,稍后一些时间也会发布在我的博客里,感兴趣的到时候可以看一下,希望可以帮助大家对装饰器有更好的理解。

Python函数篇(5)-装饰器及实例讲解的更多相关文章

  1. Python函数篇:装饰器

    装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理. ...

  2. python函数与方法装饰器

    之前用python简单写了一下斐波那契数列的递归实现(如下),发现运行速度很慢. def fib_direct(n): assert n > 0, 'invalid n' if n < 3 ...

  3. python基础篇_004_装饰器函数

    python装饰器函数 1.装饰器函数引导 功能:计算函数执行时长 import time """ 方式一: 函数首位添加时间,差值就是函数执行时间 缺点:每个函数都要加 ...

  4. python 函数基础及装饰器

    没有参数的函数及return操作 def test1(): print ("welcome") def test2(): print ("welcomt test2&qu ...

  5. python函数学习之装饰器

    装饰器 装饰器的本质是一个python函数,它的作用是在不对原函数做任何修改的同时,给函数添加一定的功能.装饰器的返回值也是一个函数对象. 分类: 1.不带参数的装饰器函数: def wrapper( ...

  6. python函数:叠加装饰器、迭代器、自定义迭代器、生成式

    一.叠加多个装饰器二.迭代器三.自定义迭代器四.xxx生成式 一.叠加多个装饰器 # 加载装饰器就是将原函数名偷梁换柱成了装饰器最内层那个wrapper函数 # 在加载完毕后,调用原函数其实就是在调用 ...

  7. python 基础篇 12 装饰器进阶

    本节主要内容:1. 通⽤装饰器回顾2. 函数的有⽤信息3. 带参数的装饰器4. 多个装饰器同时装饰⼀个函数 ⼀. 通⽤装饰器的回顾开闭原则: 对增加功能开放. 对修改代码封闭装饰器的作⽤: 在不改变原 ...

  8. python之循序渐进学习装饰器

    python装饰器的定义:在代码运行期间在不改变原函数定义的基础上,动态给该函数增加功能的方式称之为装饰器(Decorator) 装饰器的优点和用途: 1. 抽离出大量函数中与函数功能本身无关的的雷同 ...

  9. python学习笔记(五):装饰器、生成器、内置函数、json

    一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里 ...

随机推荐

  1. java使用for循环做猜数字游戏

    package org.llh.test;import java.util.Random;import java.util.Scanner;/** * 猜数字游戏 *  * @author llh * ...

  2. 关于01背包求第k优解

    引用:http://szy961124.blog.163.com/blog/static/132346674201092775320970/ 求次优解.第K优解 对于求次优解.第K优解类的问题,如果相 ...

  3. Linux替换命令

    :s/^.*$/\L&/100 ##将100行内的小写转换成大写 vi/vim 中可以使用 :s 命令来替换字符串. :s/vivian/sky/ 替换当前行第一个 vivian 为 sky ...

  4. Photoshop 学习中

    快捷键: f8打开信息调板,注意虽然数字最高是255,但0也是数值之一,因此共256级. f7开启图层调板 f6调出调色板,按D还原为默认颜色 ctrl + 放大,ctrl - 缩小 f 可以切换显示 ...

  5. phpmailer 发送邮件(一)

    phpmailer下载地址: PHPMailer : https://github.com/PHPMailer/PHPMailer 一.基本要求 Web访问正常(apache可以正常访问) php 设 ...

  6. 从零开始搭建Vue组件库——VV-UI

    前言: 前端组件化是当今热议的话题之一,也是我们在开发单页应用经常会碰到的一个问题,现在我们有了功能非常完善的Element-UI.各个大厂也相继宣布开源XXX-UI.但是也会存在一些问题,比如每个公 ...

  7. VMware14.0.0 版本虚拟机安装Ubuntu16.04 LTS版本Linux系统(多图详细步骤)

    一.前期准备工作 1.成功安装完成VMware14软件: 2.去Ubuntu官网下载Ubuntu16.0.4 LTS 版本的镜像文件. 二.安装步骤 1.打开VMware软件,选择<创建虚拟机& ...

  8. 【5】namenode启动过程

    1.格式化空间(第一次启动的操作): 命令:bin/hadoop -format //用于格式化HDFS,如果不是首次格式化,需要删除下面配置的tmp目录后再进行core-site.xml的配置: / ...

  9. 用C#操作IIS创建虚拟目录和网站

    #region CreateWebsite 添加网站 public string CreateWebSite(string serverID, string serverComment, string ...

  10. HQL连接查询和注解

    HQL连接查询和注解 一:HQL连接查询 各种连接查询: 内连接:inner join或join From Entity inner [inner] join [fetch] Entity.prope ...