小白的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 生成器并行运算
一.概述 我们已经明白生成器内部的结构,其实就是通过像函数这样的东西实现的! 多线程和单线程:简单来说多线程就是并行运算,单线程就是串行运算 二.生成器执行原理 第一步:生成一个生成器 第二步:执行 ...
随机推荐
- Python:多线程编程
1.IO编程 IO(input/output).凡是用到数据交换的地方,都会涉及io编程,例如磁盘,网络的数据传输.在IO编程中,stream(流)是一种重要的概念,分为输入流(input strea ...
- Lucene入门-安装和运行Demo程序
Lucene版本:7.1 一.下载安装包 https://lucene.apache.org/core/downloads.html 二.安装 把4个必备jar包和路径添加到CLASSPATH \lu ...
- 如何编写单元测试-基于Spring
单元测试 首先单元测试真的算是一种"脏活累活",但是我个人感觉还是有必要,至少本人最近开始写单元测试后还是能发现一些"bug"的. 如何写单元测试 单元测试的要 ...
- Unity3D获取资源的方法整理:
在使用Unity3D做项目时,获取资源的方法大致分为两种.一种是通过写代码的方式,在程序运行时,自动获取资源:一种是通过手动拖拽的方式进行获取.不管是什么类型的资源都能通过这两种方式获得,下面拿图片资 ...
- LINQ学习系列-----2.1 一个Linq语句
Linq语句介绍 先上源码: 上述代码涵盖了Linq新特性: 代码解析: 针对本文中的几点特性,前面有文章进行阐述.
- mysql导入导出命令(Linux+Windows)
Linux环境: 壹.首先查看mysql的数据存放路径:ps -ef|grep mysql 贰.进入上述查出的mysql数据存放路径:cd var/lib/mysql (数据存放路径) 叁.导出 ...
- [Docker网络]模拟一台交换机的拓扑
[Docker网络]模拟一台交换机的拓扑 本例主要对Docker网络进行实际运用. 背景介绍 一台虚拟机如何模拟成一台多端口交换机分别连接多台虚拟机? bridge网桥技术 实验准备 docker d ...
- hdu 3183 A Magic Lamp RMQ ST 坐标最小值
hdu 3183 A Magic Lamp RMQ ST 坐标最小值 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183 题目大意: 从给定的串中挑 ...
- SQL Server学习之路(一):建立数据库、建立表
0.目录 1.前言 2.建立数据库 2.1 通过SSMS建立数据库 2.2 通过SQL语句建立数据库 3.建立表 3.1 通过SSMS建立表 3.2 通过SQL语句建立表 1.前言 配置是win10+ ...
- 用python的requests第三方模块抓取王者荣耀所有英雄的皮肤
本文使用python的第三方模块requests爬取王者荣耀所有英雄的图片,并将图片按每个英雄为一个目录存入文件夹中,方便用作桌面壁纸 下面时具体的代码,已通过python3.6测试,可以成功运行: ...