装饰器

装饰器形成的过程:最简单的装饰器——有返回值的——有一个参数——万能参数
装饰器的作用:不想修改函数的调用方式 但是还想在原来的函数前后添加功能
原则:开放封闭原则
语法糖:@装饰器函数名
装饰器的固定模式

原则:开放封闭原则
开放:对扩展是开放的
封闭:对修改是封闭的

首先我们来逐步实现这么一个功能吧

计算代码运行的时间

#先来看下需要的组件
import time  #time 模块

time.time()       #获取当前时间
time.sleep(5)      #让程序睡眠多少时间

print(time.time()) #来试下

我们来写一个可以计算时间的函数

def func():
    start=time.time()
    time.sleep(0.1)   #时间太短 系统会显示 0.0,所以我们让他休眠 0.1s
    print("计算程序执行的时间")
    end=time.time()
    print(end-start)

func()

但是这里有一个问题:如果要计算很多函数的运行时间,那不是要在函数中都加上几行计算的代码,这显然是不可行的,一般写好的没问题的函数,是不会去对它进行修改,而且还很麻烦

所以这里我们写一个计算时间的函数独立出来

def times(f):
    start=time.time()
    time.sleep(0.1)
    f()
    end=time.time()
    print(end-start)

def func():
    print("计算程序执行的时间")

def func2():
    print(time.sleep(5))

times(func)
times(func2)

但是这样貌似还有一个问题,我要计算时间的函数都要调用 times() 函数,这样其实是很麻烦的

最终还是要调用 func() 就可以计算运行时间,就是说你调用的是 func() 其实调用的 times() 这就很完美了

接着我们来了解下装饰器吧,解决这样的问题

先来写一个简单的装饰器

#一个简单的装饰器
import time
def func():
    time.sleep(0.1)
    print('你好,世界')

def timmer(f):  #装饰器函数
    def inner():
        start = time.time()
        f()    #被装饰的函数
        end = time.time()
        print(end - start)
    return inner

func = timmer(func)    #通过这一步就可以使用 func 调用 timmer 了
func()

我们这里做的事情就是:在不想修改函数的调用方式的情况下  但还想在原来的函数前后添加功能

接着我们来看另一个甜甜的东西——语法糖

import time

def timmer(f):  #装饰器函数
    def inner():
        start = time.time()     time.sleep(0.1) 
        f()        #被装饰的函数
        end = time.time()
        print(end - start)
    return inner

@timmer              #语法糖  替代下面 func = timmer(func) 这句话
def func():
    time.sleep(0.1)
    print('你好,世界')

#func = timmer(func)    #通过这一步就可以使用 func 调用 timmer 了
func()        

然后我们来看接收返回值的装饰器

import time

def timmer(f):      #装饰器函数
    def inner():
        start=time.time()
        time.sleep(0.1)
        ret = f()         #被装饰的函数
        end=time.time()
        print(end-start)
        return ret  #接收 func() 函数的返回值
    return inner    #这个地方要穿函数的名字 而不是加括号

@timmer             #语法糖 替代下面 func = timmer(func) 这句话
def func():
    print('你好,世界')
    return 'Hello'

print(func())       #返回值打印  返回值为:Hello

最后我们来看带参数的装饰器,一个参数与万能参数是一样的,只是参数的不同罢了

#一个参数的装饰器
import time

def timmer(f):      #装饰器函数
    def inner(a):   #3.给 inner() 加上参数
        start=time.time()
        time.sleep(0.1)
        ret = f(a)  #4.由于 inner() 把参数传给了 f(),所以 f() 也要加上参数,最后测试传值
        end=time.time()
        print(end-start)
        return ret  #接收 func() 函数的返回值
    return inner

@timmer             #语法糖 替代下面 func = timmer(func) 这句话
def func(a):        #2.这里也要加上参数,由于执行 func 时,实际执行的 inner(),所以 inner() 也要加上参数
    print("计算程序执行的时间",a)
    return 'Hello'

"))  #1.加入参数

#输出结果
'''
计算程序执行的时间 123
0.10937380790710449
Hello
'''
###万能参数的装饰器
#可以看出 只是在 a 的位置更换了 *args **kwargs 来接收参数
import time

def timmer(f):
    def inner(*args,**kwargs):
        start=time.time()
        time.sleep(0.1)
        ret = f(*args,**kwargs)
        end=time.time()
        print(end-start)
        return ret
    return inner

@timmer
def func(*args,**kwargs):
    print("计算程序执行的时间",args,kwargs)    #2. 就是这个位置的 kwargs,如果写了,打印时会出现一个 ' {} ' 空字典,并不会报错
    return 'Hello'

',k=100))    #1. 不需要关键字传参时,kwargs 可以不写

#输出结果
'''
计算程序执行的时间 ('1', '2', '3') {'k': 100}
0.1093745231628418
Hello
'''

好了,以上就是我们对于装饰器完善的最终结果了

装饰器的固定模式

def wrapper(f):     #装饰器函数,f是被装饰的函数
    def inner(*args,**kwargs):    #定义一个内置函数,且和下面统级别的返回值名字一致且不加括号
                                  #动态参数一定要原封不动的传给 被装饰的函数 f()
        '''在被装饰函数之前要做的事'''
        ret = f(*args,**kwargs)   #被装饰的函数  函数执行完的返回值要原封不动传给 return
        '''在被装饰函数之后要做的事'''
        return ret
    return inner

@wrapper         #语法糖 @装饰器函数名 等价于 func = wrapper(func)
def func(a,b):     #被装饰的函数
    time.sleep(0.01)
    print('你好:世界',a,b)
    return '新年好'
#print(func(23,45))  #接收返回值
ret = func(23,45)   #接收返回值
print(ret)

day 11 - 1 装饰器的更多相关文章

  1. day 11 - 2 装饰器练习

    1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件)要求登录成功一次,后续的函数都无需再输入用户名和密码 FLAG = False def login(func): def inner ...

  2. Django-website 程序案例系列-11 验证装饰器

    FBV装饰器: def auth(func): #装饰器函数 def inner(request, *args, **kwargs): v = request.COOKIES.get('usernam ...

  3. Python学习:11.Python装饰器讲解(二)

    回顾 上一节我们进行了Python简单装饰器的讲解,但是python的装饰器还有一部分高级的使用方式,这一节就针对python装饰器高级部分进行讲解. 为一个函数添加多个装饰器 今天,老板又交给你一个 ...

  4. python 装饰器、递归原理、模块导入方式

    1.装饰器原理 def f1(arg): print '验证' arg() def func(): print ' #.将被调用函数封装到另外一个函数 func = f1(func) #.对原函数重新 ...

  5. Python核心编程 | 装饰器

        装饰器是程序开发的基础知识,用好装饰器,在程序开发中能够提高效率 它可以在不需要修改每个函数内部代码的情况下,为多个函数添加附加功能,如权限验证,log日志等   涉及点:   1.先梳理一下 ...

  6. 面向对象程序设计(OOP设计模式)-结构型模式之装饰器模式的应用与实现

    课程名称:程序设计方法学 实验4:OOP设计模式-结构型模式的应用与实现 时间:2015年11月18日星期三,第3.4节 地点:理1#208 一.实验目的 加深对结构型设计模式的理解以及在开发中的实际 ...

  7. Python小白学习之函数装饰器

    装饰器 2018-10-25 13:49:37 装饰器从字面意思就是用来装饰的,在函数可以理解为:在函数中,我们不想影响原来的函数功能,又想给函数添加新的功能,这时候我们就用到了装饰器. 一般函数操作 ...

  8. 函数与装饰器Python学习(三)

    1.1 文件处理 1.1.1 打开文件过程 在Python中,打开文件,得到文件句柄并赋值给一个变量,默认打开模式就为r f=open(r'a.txt','w',encoding='utf-8') p ...

  9. 十一. Python基础(11)—补充: 作用域 & 装饰器

    十一. Python基础(11)-补充: 作用域 & 装饰器 1 ● Python的作用域补遗 在C/C++等语言中, if语句等控制结构(control structure)会产生新的作用域 ...

随机推荐

  1. Windows下将nginx安装为服务运行

    今天看到nginx这个小服务器软件正式版更新到了1.4.2,想玩下它.这个服务器软件虽小,但功能强大,是开源软件,有着良好的性能,被很多个人.企业,甚至大型企业所使用! 由于是在Windows下,所以 ...

  2. 计算机开放电子书汇总(包括二十多本python相关的图书教程)

    计算机开放电子书汇总(包括二十多本python相关的图书教程) https://github.com/it-ebooks/it-ebooks-archive 这个汇总包含了各种计算机相关的开放图书和文 ...

  3. HttpWebRequest出错 服务器提交了协议冲突. Section=ResponseHeader Detail=CR 后面必须是 LF

    服务器提交了协议冲突. Section=ResponseHeader Detail=CR 后面必须是 LF  The server committed a protocol violation. Se ...

  4. 分布式学习材料Distributed System Prerequisite List

    接下的内容按几个大类来列:1. 文件系统a. GFS – The Google File Systemb. HDFS1) The Hadoop Distributed File System2) Th ...

  5. DOM,BOM

    1.DOM:文档对象模型(Document Object Model) 1)子节点:只是这一代的后代,不会计算后代的后代  1.childNodes:获取子节点,    --IE6-8:获取的是元素节 ...

  6. .Net中的Debug模式和Release模式

    1.Debug模式和Release模式 在vs中,运行程序有两种模式:Debug和Release 在bin目录下也会生成对应的文件夹,用于存放生成的dll等文件,这两种模式的区别如下: Debug:用 ...

  7. pandas 练习

    from pandas import Series, DataFrame # Series接收list或dict作为一维数据 #两个属性:values, index #① s1 = Series([4 ...

  8. Effective Objective-C 2.0之Note.02

    1.多用类型常量,少用#define预处理指令 不要用预处理指令定义常量.这样定义出来的常量不含类型信息,编译器只是会在编译前据此执行查找与替换操作.即使有人重新定义了常量值,编译器也不会产生警告信息 ...

  9. C#设计模式(6)——原型模式

    一.概念 二.模型 三.代码实现 ///火影忍者中鸣人的影分身和孙悟空的的变都是原型模式 class Client { static void Main(string[] args) { // 孙悟空 ...

  10. java爬虫HttpURLConnect获取网页源码

    public abstract class HttpsURLConnection extends HttpURLConnection HttpsURLConnection 扩展 HttpURLConn ...