小白的Python之路 day4 装饰器高潮
首先装饰器实现的条件:
高阶函数+嵌套函数 =》装饰器
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 装饰器高潮的更多相关文章
- 小白的Python之路 day4 装饰器前奏
装饰器前奏: 一.定义: 1.装饰器本质是函数,语法都是用def去定义的 (函数的目的:他需要完成特定的功能) 2.装饰器的功能:就是装饰其他函数(就是为其他函数添加附加功能) 二.原则: 1. 不能 ...
- python之路之装饰器
一 装饰器进化之路1) import time def index(): start_time=time.time() time.sleep() print('welcome to index wor ...
- [Python之路] 使用装饰器给Web框架添加路由功能(静态、动态、伪静态URL)
一.观察以下代码 以下来自 Python实现简易HTTP服务器与MINI WEB框架(利用WSGI实现服务器与框架解耦) 中的mini_frame最后版本的代码: import time def in ...
- 小白的Python之路 day4 生成器
一.列表生成式 看下面例子: 列表生成式的作用:主要是让代码更简洁(还有装X的效果) 二.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...
- 小白的Python之路 day4 迭代器
迭代器 学习前,我们回想一下可以直接作用于for循环的数据类型有以下几种: 1.集合数据类型,如list.tuple.dict.set.str等: 2.是generator,包括生成器和带yield的 ...
- 小白的Python之路 day4 json and pickle数据标准序列化
一.简述 我们在写入文件中的数据,只能是字符串或者二进制,但是要传入文件的数据不一定全是字符串或者二进制,那还要进行繁琐的转换,然后再读取的时候,还要再转回去,显得很麻烦,今天就来学习标准的序列化:j ...
- 小白的Python之路 day4 软件目录结构规范
软件目录结构规范 为什么要设计好目录结构? "设计项目目录结构",就和"代码编码风格"一样,属于个人风格问题.对于这种风格上的规范,一直都存在两种态度: 一类同 ...
- 小白的Python之路 day4 不同目录间进行模块调用(绝对路径和相对路径)
一.常用模块调用函数功能解释 1.__file__ 功能:返回自身文件的相对路径 你从pycharm的执行结果可以看出,在pycharm执行atm.py文件时,是从绝对路径下去执行的,而你从cmd下去 ...
- 小白的Python之路 day4 生成器并行运算
一.概述 我们已经明白生成器内部的结构,其实就是通过像函数这样的东西实现的! 多线程和单线程:简单来说多线程就是并行运算,单线程就是串行运算 二.生成器执行原理 第一步:生成一个生成器 第二步:执行 ...
随机推荐
- PHP时间戳和日期互转换
在php中我们要把时间戳转换日期可以直接使用date函数来实现,如果要把日期转换成时间戳可以使用strtotime()函数实现,下面我来给大家举例说明. 1.php中时间转换函数 strtotime ...
- JavaScript学习笔记(十五)——对象之Date,RegExp
在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...
- js学习笔记(延时器)
//setTimeout() //功能:设置一个延时器 //语法:var timer = window.setTimeout(code,millisec); //参数: code:是任何合 ...
- PCA, SVD以及代码示例
本文是对PCA和SVD学习的整理笔记,为了避免很多重复内容的工作,我会在介绍概念的时候引用其他童鞋的工作和内容,具体来源我会标记在参考资料中. 一.PCA (Principle component a ...
- kubernetes nginx ingress 使用记录
前言 ingress是一种可以暴露k8s集群内部service的方式,用户编辑配置文件定义一个ingress资源即可实现外部网络访问内网service. ingress controller是来管理所 ...
- c++用类写栈和队列的简单基本操作(实验)
继续更文.这次用类来写栈和队列,都是用数组模拟的: 以下是栈和队列的定义: 然后分别是栈和队列的类: 完整代码贴上: 栈 //使用类来定义栈 class ZHAN { public: STACK s; ...
- setTimeout和setInterval和单线程
我们知道,js是单线程执行的(单线程j就是说在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行).所以其实setTimeout和setInterval所谓的"异 ...
- JS对象属性命名规则
JS标识符的命名规则,即变量的命名规则: 标识符只能由字母.数字.下划线和'$'组成 数字不可以作为标识符的首字符 对象属性的命名规则 通过[]操作符为对象添加属性时,属性名称可以是任何字符串(包括只 ...
- Java爬虫——B站弹幕爬取
如何通过B站视频AV号找到弹幕对应的xml文件号 首先爬取视频网页,将对应视频网页源码获得 就可以找到该视频的av号aid=8678034 还有弹幕序号,cid=14295428 弹幕存放位置为 h ...
- 》》stroll--各种特效下拉菜单
<!doctype html> <html lang="en"> <head> <meta charset="utf-8&quo ...