python全栈开发-Day10 装饰器(闭合函数的应用场)

 

一、 装饰器

  装饰器就是闭包函数的一种应用场景

  什么是闭包函数?我们再来回忆一下:

  闭包函数:

    定义在函数内部的函数,并且该函数包含对外部函数作用域(强调:对全局作用域名字的引用不算闭包)名字的引用,该函数称为闭包函数

  说到作用域我们再回忆下:

  作用域:
      全局范围:内置+全局
        全局有效,全局存活
      局部范围:局部
        局部有效,局部存活
  作用域关系是在函数定义阶段就规定死,与调用位置无关,
  也就是说,无论函数在哪儿调用,都必须回到当初定义函数时的位置找作用域关系

一 、为何要用装饰器

#开放封闭原则:
    #软件一旦上线后,就应该遵循开放封闭原则,对修改源代码是封闭的,对功能的扩展是开放的,也就是我们必须找到一种解决方法:
    #能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能.

二 、什么是装饰器

#装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
#强调装饰器的原则:
    #1 、不修改被装饰对象的源代码
    #2 、不修改被装饰对象的调用方式
#装饰器的目标:
    #在遵循1和2的前提下,为被装饰对象添加上新功能

三 、装饰器的使用

#我们现在给下面函数增加一个运行时间的功能
import time

def index():
    time.sleep(3)
    print('welcome to index page')

#修改一
def index():
    start_time=time.time()
    time.sleep(3)
    print('welcome to index page')
    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))

index()   #功能实现

#评语:直接改源代码,这么搞被开了。。。
#再来一位童靴,来实现功能
#修改二
import time

def index():
    time.sleep(1)
    print('welcome to index page')

start_time=time.time()
index()
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))

#评语:有好多函数要实现这个功能,写N遍变这个代码,
#后期维护一脸懵逼,还是被开。。。
#再来一位童靴,功能重复实现看我用强大的函数
#修订三:
import time

def index():
    time.sleep(3)
    print('welcome to index page')

def wrapper(func):  #func=index
    start_time=time.time()
    func() #index()
    stop_time = time.time()
    print('run time is %s' % (stop_time - start_time))

wrapper(index) 

#评语:修改了原函数的调用方式,依然被开。。。
#终于来了位小牛的童靴,函数的值可以返回,然后我再把重新定义index
#修订四:
import time

def index():
    time.sleep(3)
    print('welcome to index page')

def outter(func): #func=最原始的index
    # func=最原始的index
    def wrapper():
        start_time=time.time()
        func()
        stop_time=time.time()
        print(stop_time-start_time)
    return wrapper

index=outter(index)  # 新的index=wrapper
index()  #wrapper()  功能基本实现
#评语:在原值没有返回值是没问题,但是有返回值的情况下,这么搞就会发现返回的是None
#这次小牛牛童靴路过看到这情况,say这么搞!
#修订五
import time
def index():
    time.sleep(1)
    print('welcome to index page')
    return 123     #假使这里返回123     返回值可以是任意类型 

#==============下面就是装饰器
def timmer(func):
    #func=最原始的index
    def wrapper(*args,**kwargs):     #可变长参数
        start_time=time.time()
        res=func(*args,**kwargs)  #调用最原始的index
        stop_time=time.time()
        print(stop_time-start_time)
        return res        #index()运行的返回值
    return wrapper

index=timmer(index) # 新的index=wrapper

print(index())    #功能已经实现,返回值123

#评语:这里的装饰的功能已经实现,返回的值也得到,小牛牛不是白叫的
#天上五彩红光,大牛童靴出现!各位童靴火速围观!
import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper

@timmer #index=timmer(index)      装饰器的标准格式!
def index():
    time.sleep(1)
    print('welcome to index page')
    return 123

@timmer # home=timmer(home)
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)

# index()
#home('egon')   

#评语:大牛就是大牛!大牛say:教你们绝技,不会的童靴可以照下面的模板实现:

#无参装饰器模板
def outer(func):     #outer,inner名字功能随意
    def inner(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return inner

@outer            #装饰器要在装饰函数的上方
def duoduo():
    pass                      

四 、装饰器语法

#被装饰函数的正上方,单独一行
@deco1
@deco2
@deco3
def foo():
    pass
#foo=deco1(deco2(deco3(foo)))
#这里的思想就是最上面装饰器,装饰的下面所有的函数(deco2,deco3,foo)
#然后deco2装饰(deco3,foo),最后deco3装饰foo
#功能的不同,放的顺序也要注意,不然装饰的效果可能实现的就不对了!

五、多个装饰器的使用:

import time
current_user={
    'username':None,
    # 'login_time':None
}

def auth(func):
    # func=index
    def wrapper(*args,**kwargs):
        if current_user['username']:   #这里是认证过的,下次就不用认证
            print('已经登陆过了')
            res=func(*args,**kwargs)
            return res

        uname=input('用户名>>: ').strip()
        pwd=input('密码>>: ').strip()
        if uname == 'egon' and pwd == '123':
            print('登陆成功')
            current_user['username']=uname
            res=func(*args,**kwargs)
            return res
        else:
            print('用户名或密码错误')
    return wrapper

def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper

@timmer # timmer 统计的是auth+index的执行时间
@auth             #我们只装饰index的话就要把@timmer紧跟index
def index():
    time.sleep(1)
    print('welcome to index page')
    return 123

@auth
@timmer     #这里统计的就是home运行的时间
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)

#index()
#home("duoduo")

六、有参数的装饰器的使用:

import time
current_user={
    'username':None,
    # 'login_time':None
}

def auth(engine):    #道理还是那个道理,在外面包了一层engine的值
    # engine='file'  #这个值外面穿什么进来就是什么
    def auth2(func):
        # func=index
        def wrapper(*args,**kwargs):
            if engine == 'file':
                if current_user['username']:
                    print('已经登陆过了')
                    res=func(*args,**kwargs)
                    return res

                uname=input('用户名>>: ').strip()
                pwd=input('密码>>: ').strip()
                if uname == 'egon' and pwd == '123':
                    print('登陆成功')
                    current_user['username']=uname
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('用户名或密码错误')
            elif engine == 'mysql':         #engine 值得判断情况
                print('基于MyQL的认证')
            elif engine == 'ldap':
                print('基于LDAP的认证')
        return wrapper
    return auth2     #这里也要返回auth2的内存地址

@auth('ldap') #@auth2 #index=auth2(index) #index=wrapper
def index():
    time.sleep(1)
    print('welcome to index page')
    return 123

index() # wrapper()

python开发装饰器的应用的更多相关文章

  1. 详解Python的装饰器

    Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...

  2. 浅谈Django的中间件与Python的装饰器

    浅谈Django的中间件 与Python的装饰器 一.原理 1.装饰器是Python的一种语法应用,利用闭包的原理去更改一个函数的功能,即让一个函数执行之前先到另外一个函数中执行其他需求语句,在执行该 ...

  3. 进阶Python:装饰器 全面详解

    进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...

  4. Python 之装饰器

    Python 的装饰器可谓是提高开发效率的一大利器.然而初学装饰器的时候感觉很难理解,因为除了 Python 之外没听说哪个语言有这种东西. 而且网上看的很多解释看似容易理解,但只能很快理解了装饰器能 ...

  5. 我终于弄懂了Python的装饰器(一)

    此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 一 ...

  6. Python各式装饰器

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  7. Python札记 -- 装饰器补充

    本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...

  8. python基础——装饰器

    python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...

  9. 【转】详解Python的装饰器

    原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...

随机推荐

  1. STM32——GPIO之从库函数到寄存器的前因后果

    例子为单片机的"Hello World"级的流水灯实验--虽然只有一个,其中并不是将完整的代码给出,只是给出关键部分来说明"如何调用ST公司的的库来完成对硬件的控制,以及 ...

  2. C#利用 string.Join 泛型集合快速转换拼接字符串

    C#利用 string.Join 泛型集合快速转换拼接字符串 List<int> superior_list = new List<int>(); superior_list. ...

  3. 【原】关于定时回查出现的BUG有感

    前言:今天有同事反映说客户在平台投标后,看到的是失败状态,但是钱在某银行的状态是被冻结了,我这边给出答复是只有投标成功才会冻结. 首先写下流程:P2P对接某银行托管,某银行的部分接口要求我们通过同步回 ...

  4. C#图解教程 第二十二章 异常

    异常 什么是异常try语句 处理异常 异常类catch 子句使用特定catch子句的示例catch子句段finally块为异常寻找处理程序更进一步搜索 一般法则搜索调用栈的示例 抛出异常不带异常对象的 ...

  5. Aspose.Words for .NET

    Aspose.Words for .NET Aspose.Words for .NET是 .NET 下先进的 Word 文档处理 API.它支持 DOC, OOXML, RTF, HTML, Open ...

  6. [HDU5765]Bonds

    题面 题意 给出一张\(n\)点\(m\)边无向连通图,求每条边出现在多少个割集中. \(n\le20,m\le\frac{n(n-1)}{2}\) sol 所谓割集,就是指把\(n\)个点分成两个集 ...

  7. 自增ID算法snowflake(雪花)

    在数据库主键设计上,比较常见的方法是采用自增ID(1开始,每次加1)和生成GUID.生成GUID的方式虽然简单,但是由于采用的是无意义的字符串,推测会在数据量增大时造成访问过慢,在基础互联网的系统设计 ...

  8. WordPress修改标签云大小及颜色

    修改WordPress标签字体大小: 在cpanel面板中依次打开「wp-includes」→「category-template.php」,找到wp_tag_cloud, 1 2 3 4 5 6 7 ...

  9. 通过IF({1,0}和VLOOKUP函数实现Excel的双条件多条件查找的方法

    在Excel中,通过VLOOKUP函数可以查找到数据并返回数据.不仅能跨表查找,同时,更能跨工作薄查找. 但是,VLOOKUP函数一般情况下,只能实现单条件查找. 如果想通过VLOOKUP函数来实现双 ...

  10. Cucumber 行为驱动开发简介

    Cucumber 是一个能够理解用普通语言 描述的测试用例的支持行为驱动开发(BDD)的自动化测试工具,用Ruby编写,支持Java和.Net等多种开发语言. 现在看看Cucumber中用到的术语 . ...