首先装饰器实现的条件:

高阶函数+嵌套函数 =》装饰器

1.首先,我们先定义一个高级函数,去装饰test1函数,得不到我们想要的操作方式

 import time

 #定义高阶函数
 def deco(func):
     start_time = time.time()
     func()
     stop_time = time.time()
     print("the func run time is %s"%(stop_time-start_time))

 #装饰test1函数

 def test1():
     time.sleep(3)
     print("in the test1")
 #deco(test1)  #这样操作就改变函数的调用方式 , 怎样操作不改变调用方式
 test1 = deco(test1)  #想想前提是用return 返回值

 #输出
 in the test1
 the func run time is 3.0002999305725098

2 .用高阶函数的返回值方法,得到了想要的调用方式,但是结果不是想要的,一直到现在我们一直在用高阶函数

 import time

 #定义高阶函数
 def deco(func):
     start_time = time.time()
     return func()
     stop_time = time.time()
     print("the func run time is %s"%(stop_time-start_time))

 #装饰test1函数

 def test1():
      time.sleep(3)
      print("in the test1")

 test1()     #调用方式问题解决了,但是结果不是想要的结果

 结果
 in the test1

3 . 再用嵌套函数得到了我们想要的结果和不变的调用方式(哇喔,是不是好牛X)

 import time

 #定义内置函数
 def timmer(func):  #timmer(test1) func=test1
     def deco():
         start_time = time.time()
         func()   #run test1()
         stop_time = time.time()
         print("the func run time is %s"%(stop_time-start_time))

     return deco  #重点的重点

 #装饰test1函数
 @timmer  # 相当于test1 = timmer(test1)   牛X的方法
 def test1():
     time.sleep(3)
     print("in the test1")

 #直接执行test1函数
 test1()

 #输出
 in the test1
 the func run time is 3.0002999305725098

4.  我们用装饰器去装饰一个带参数的函数会怎么样?

 import time

 def timmer(func):
     def deco():
         start_time = time.time()
         func()   #run test2()  这里没有参数,报错
         stop_time = time.time()
         print("the func run time is %s"%(stop_time-start_time))

     return deco  

 @timmer
 def test2(name,age):
     print("name:%s,age:%s"%(name,age))

 test2()

 #输出
 Traceback (most recent call last):
   File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 16, in <module>
     test2()
   File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 6, in deco
     func()   #run test2()
 TypeError: test2() missing 2 required positional arguments: 'name' and 'age' #缺少传入name和age参数

结果:很显然是错误的。因为这边执行的test2函数其实就是执行的deco函数,deco函数体内的func()其实就是执行test2函数,但是,test2需要传入name和age两个参数,所以报错。那怎么解决呢?

5. 我们只能传入参数了,但是你又不能确定传入几个参数,所以我们只能用非固定参数传参。代码如下:(哇喔,这个更牛X)

 import time

 def timmer(func):  #timmer(test1) func=test1
     def deco(*args,**kwargs):  #传入非固定参数  可以面对各种参数
         start_time = time.time()
         func(*args,**kwargs)   #传入非固定参数
         stop_time = time.time()
         print("the func run time is %s"%(stop_time-start_time))

     return deco

 #不带参数
 @timmer  # 相当于test1 = timmer(test1)
 def test1():
     time.sleep(3)
     print("in the test1")

 #带参数
 @timmer
 def test2(name,age):
     print("name:%s,age:%s"%(name,age))
 #调用
 test1()
 test2("qianduoduo",22)

 #输出
 #test1
 in the test1
 the func run time is 3.0010883808135986
 #test2
 name:qianduoduo,age:22
 the func run time is 0.0  #test2

6.我就问还有没有终极版的,答案是:有

前面的都是小高潮(基本上也能满足百分之九十的需求),现在正式介绍终极的高潮版的 语法糖(我也不知道为什么取这个名字)也叫装饰器

 import time
 user,passwd = 'qian','zxc123'
 def auth(func):
     def wrapper(*args,**kwargs):   #包装
         username = input("Username:").strip()
         password = input("Password:").strip()

         if user == username and passwd == password:
             print("\033[32;1mUser has passed authentication\033[0m")
             func(*args,**kwargs)
         else:
             exit("\033[31;1mInvalid username or password\033[0m")
     return wrapper

 def index():  #建立网站的首页  首页不需要登入
     print("welcome to index page")
 @auth    #加上装饰器
 def home():  #自己的页面,需要登入
     print("welcome to home page")
 @auth
 def bbs():  #论坛区的页面,需要登入
     print("welcome to bbs page")

 index()

 home()

 bbs()
 运行结果:  #运行很完美,堪称经典之作
 welcome to index page
 Username:qian
 Password:zxc123
 User has passed authentication
 welcome to home page
 Username:qian
 Password:zxc123
 User has passed authentication
 welcome to bbs page

7.走到这地方,我的问题来了,我的home执行完没有任何数据,我现在在home中return一个数据,看代码:

 import time
 user,passwd = 'qian','zxc123'
 def auth(func):
     def wrapper(*args,**kwargs):   #包装
         username = input("Username:").strip()
         password = input("Password:").strip()

         if user == username and passwd == password:
             print("\033[32;1mUser has passed authentication\033[0m")
             func(*args,**kwargs)
         else:
             exit("\033[31;1mInvalid username or password\033[0m")
     return wrapper

 def index():  #建立网站的首页  首页不需要登入
     print("welcome to index page")
 @auth    #加上装饰器
 def home():  #自己的页面,需要登入
     print("welcome to home page")
     return "from home"  #假设这就是我返回的数据
 @auth
 def bbs():  #论坛区的页面,需要登入
     print("welcome to bbs page")

 index()

 print(home())  #home的执行结果

 bbs()

 结果:
 welcome to index page
 Username:qian
 Password:zxc123
 User has passed authentication
 welcome to home page
 None   # home的执行结果,没有执行结果
 #(虽然装饰器没改变源代码,没改变调用方式,但是改变了执行结果)
 # 这时候我们怎么办,怎么获得home的返回结果?
 Username:

8 我们来分析一下,按照顺序①②③

 import time
 user,passwd = 'qian','zxc123'
 def auth(func):
     def wrapper(*args,**kwargs):   #包装
         username = input("Username:").strip()
         password = input("Password:").strip()

         if user == username and passwd == password:
             print("\033[32;1mUser has passed authentication\033[0m")
             func(*args,**kwargs)  #from home
             #   ①  func的执行结果没有传给谁,那就没了,就是None
         else:
             exit("\033[31;1mInvalid username or password\033[0m")
     return wrapper #③wrapper执行了,没有返回值

 def index():  #建立网站的首页  首页不需要登入
     print("welcome to index page")
 @auth    #加上装饰器
 def home():  #自己的页面,需要登入
     print("welcome to home page")
     return "from home"
 @auth
 def bbs():  #论坛区的页面,需要登入
     print("welcome to bbs page")

 index()

 print(home())  #②调用home 时候,就是调用wrapper()
 bbs()
                 

9 分析完得出以下代码:

 import time
 user,passwd = 'qian','zxc123'
 def auth(func):
     def wrapper(*args,**kwargs):   #包装
         username = input("Username:").strip()
         password = input("Password:").strip()

         if user == username and passwd == password:
             print("\033[32;1mUser has passed authentication\033[0m")
            # return   func(*args,**kwargs)  函数到这里就结束了
             res = func(*args,**kwargs) #增加变量
             print("---after authenticaion")  #再装饰点其他东西
             return res
         else:
             exit("\033[31;1mInvalid username or password\033[0m")
     return wrapper

 def index():  #建立网站的首页  首页不需要登入
     print("welcome to index page")
 @auth    #加上装饰器
 def home():  #自己的页面,需要登入
     print("welcome to home page")
     return "from home"
 @auth
 def bbs():  #论坛区的页面,需要登入
     print("welcome to bbs page")

 index()

 print(home())

 bbs()

 结果
 welcome to index page
 Username:qian
 Password:zxc123
 User has passed authentication
 welcome to home page
 ---after authenticaion
 from home
 Username:qian
 Password:zxc123
 User has passed authentication
 welcome to bbs page
 ---after authenticaion

10不过这不是我要讲的高潮部分,而是补充前面的前奏

同志们在真正的现实生活中,账号认证方式有多种,现在的认证方式是本地认证,下面才是真正的终极

 import time
 user,passwd = 'qian','zxc123'
 def auth(auth_type):
     print("auth func:",auth_type)
     def outer_wrapper(func):
         def wrapper(*args,**kwargs):   #包装
             if auth_type == "local":
                 username = input("Username:").strip()
                 password = input("Password:").strip()
                 if user == username and passwd == password:
                     print("\033[32;1mUser has passed authentication\033[0m")
                     res = func(*args,**kwargs)
                     print("---after authenticaion")
                     return res
                 else:
                     exit("\033[31;1mInvalid username or password\033[0m")
             elif auth_type == "ldap":
                 print("搞毛线ldap,不会")
         return wrapper
     return outer_wrapper    

 def index():  #
     print("welcome to index page")
 @auth(auth_type = "local")   #本地的文件认证  home = wrapper
 def home():
     print("welcome to home page")
     return "from home"
 @auth(auth_type ="ldap")     #ldap认证
 def bbs():
     print("welcome to bbs page")

 index()

 print(home())  #wrapper()     

 bbs()

 结果
 auth func: local
 auth func: ldap
 welcome to index page
 Username:qian
 Password:zxc123
 User has passed authentication
 welcome to home page
 ---after authenticaion
 from home         #调用方式 home() 就没这个返回值了
 搞毛线ldap,不会

这就是我们的终极版本, 运行的具体顺序可以自己调试调试

这个函数的作用分别是:

  1.auth(auth_type) 传递装饰器的参数

  2.outer_wrapper(func) 把函数当做实参传递进来

  3.wrapper(*args,**kwargs) 真正执行装饰的函数

##home()

小白的Python之路 day4 装饰器高潮的更多相关文章

  1. 小白的Python之路 day4 装饰器前奏

    装饰器前奏: 一.定义: 1.装饰器本质是函数,语法都是用def去定义的 (函数的目的:他需要完成特定的功能) 2.装饰器的功能:就是装饰其他函数(就是为其他函数添加附加功能) 二.原则: 1. 不能 ...

  2. python之路之装饰器

    一 装饰器进化之路1) import time def index(): start_time=time.time() time.sleep() print('welcome to index wor ...

  3. [Python之路] 使用装饰器给Web框架添加路由功能(静态、动态、伪静态URL)

    一.观察以下代码 以下来自 Python实现简易HTTP服务器与MINI WEB框架(利用WSGI实现服务器与框架解耦) 中的mini_frame最后版本的代码: import time def in ...

  4. 小白的Python之路 day4 生成器

    一.列表生成式  看下面例子: 列表生成式的作用:主要是让代码更简洁(还有装X的效果) 二.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...

  5. 小白的Python之路 day4 迭代器

    迭代器 学习前,我们回想一下可以直接作用于for循环的数据类型有以下几种: 1.集合数据类型,如list.tuple.dict.set.str等: 2.是generator,包括生成器和带yield的 ...

  6. 小白的Python之路 day4 json and pickle数据标准序列化

    一.简述 我们在写入文件中的数据,只能是字符串或者二进制,但是要传入文件的数据不一定全是字符串或者二进制,那还要进行繁琐的转换,然后再读取的时候,还要再转回去,显得很麻烦,今天就来学习标准的序列化:j ...

  7. 小白的Python之路 day4 软件目录结构规范

    软件目录结构规范 为什么要设计好目录结构? "设计项目目录结构",就和"代码编码风格"一样,属于个人风格问题.对于这种风格上的规范,一直都存在两种态度: 一类同 ...

  8. 小白的Python之路 day4 不同目录间进行模块调用(绝对路径和相对路径)

    一.常用模块调用函数功能解释 1.__file__ 功能:返回自身文件的相对路径 你从pycharm的执行结果可以看出,在pycharm执行atm.py文件时,是从绝对路径下去执行的,而你从cmd下去 ...

  9. 小白的Python之路 day4 生成器并行运算

    一.概述 我们已经明白生成器内部的结构,其实就是通过像函数这样的东西实现的! 多线程和单线程:简单来说多线程就是并行运算,单线程就是串行运算 二.生成器执行原理 第一步:生成一个生成器  第二步:执行 ...

随机推荐

  1. [线段树]P1047 校门外的树

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...

  2. Python学习笔记整理总结【RabbitMQ队列】

    RabbitMQ是消息队列.之前学过的队列queue:线程queue(threading queue),只是多个线程之间进行数据交互.进程queue(processing queue),只是父进程与子 ...

  3. 【笔记】web 的回流与重绘及优化

    最近看了幕课网 web 前端性能优化的课程,其中说到了浏览器的回流(reflow) 及 重绘(repaint).觉得以后面试或许会被问到所以做一下笔记: 课程从回流及重绘这两个点延伸出了一个知识点就是 ...

  4. jsp运行原理及运行过程

    JSP的执行过程主要可以分为以下几点: 1)客户端发出请求. 2)Web容器将JSP转译成Servlet源代码. 3)Web容器将产生的源代码进行编译. 4)Web容器加载编译后的代码并执行. 5)把 ...

  5. iOS APP上架被拒重新提交审核教程

    iOS APP审核比较严格,难免会出现被拒绝的情况,需要根据苹果反馈的问题修改后重新打包上传审核! 1.登录itunesconnect.https://itunesconnect.apple.com进 ...

  6. mvc约定

    mvc是围绕一些基于约定的默认项,这写默认项在必要时可以覆盖,这个概念通常成为"约定优于配置". 比如没必要在web.config中设置views,models等文件夹的名称,已经 ...

  7. 利用vertical-align:middle垂直居中

    以前总是以为vertical-align与text-align是同样的道理,一个是垂直居中,一个是水平居中,结果在这里一点效果也没有.事实上vertical-align与text-align完全不一样 ...

  8. 中介者模式(Mediator)

    中介者模式(Mediator) 中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改.如果使用中介者模式,只 ...

  9. leetcode算法题2: 合并两个二叉树。递归,如何切入并保持清醒?

    /* Given two binary trees and imagine that when you put one of them to cover the other, some nodes o ...

  10. 有关BOM头的一些知识

    在psr开发标准中,有一条是讲的,php只能使用无bom的utf8格式 . 那么这个bom是几个意思.  说一些理论内容 . 在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK ...