一.今日内容总览

关于函数的装饰器
1.装饰器(重点,难点)(要求:反复写,代码不多但是很绕)
开闭原则:(比如,菜单是拆散的,一点点搞的,用友拆散自己的功能,以后就不用开发了)
(1)对功能的扩展开放
(2)对代码的修改是封闭的 通用装饰器语法:
def wrapper(fn):
def inner(*args,**kwargs): #聚合
#在目标函数之前的操作
ret=fn(*args,**kwargs) #打散
在目标函数之后
return inner
@wrapper #等价于 func=wrapper(func)
def func():
pass
func() NC(用友,脑残)
2.同一个函数 被多个装饰器装饰 @wrapper1
@wrapper2
@wrapper3
def func():
pass
1 2 3 func 3 2 1
总结:就近原则,一层一层写 3.带参数的装饰器(难受)(明白函数的调用就行)
def wrapper_out(参数):
def wrapper(fn):
def inner(*args,**kwargs): #聚合
#在目标函数之前
ret=fn(*args,**kwargs) #打散
#在目标函数之后
return ret
return inner
return wrapper
@wrapper_out(实参) #执行的时候,先执行函数调用,然后使用返回值和前面的@组合成装饰器语法糖
def func():
pass

二.今日内容大纲

1.开闭原则

2.装饰器

3.带参数的装饰器

4.多个装饰器装饰同一个函数

5.装饰器的应用

三.今日内容详解

1.开闭原则

开闭原则:
对功能的扩展开放;
对代码的修改是封闭的.
def chi():
print('吃东西')
print('喝东西')
chi()
chi()
#显然不是我们想要的,对程序继续优化

2.装饰器

(1)

女娲  造人 补天
热插拔:有时需要,有时不需要,这才是程序需要的
def zaoren():
# print('浇水') #此需求有的时候需要,有的时候不需要 print('捏个泥人')
print('吹口仙气')
print('就出来人了')
zaoren()
zaoren()
zaoren()
上面的写法依然没满足我们的需求

(2)

#三年大旱,没有水?
def zaoren():
# print('浇水') #此需求有的时候需要,有的时候不需要
print('捏个泥人')
print('吹口仙气')
print('就出来人了')
def water():
print('浇水')
zaoren()
zaoren() #不能一直修改这两行代码
water()
#这时的设计就不符合开闭原则

(3)装饰器的源头

# # 装饰器
def wrapper(fn): # fn接收的是一个函数
def inner():
print("浇水")
fn() # 调用你传递进来的函数
print("睡一觉")
return inner
def zaoren():
print("捏个泥人")
print("吹口仙气")
print("你就出来了")
zaoren = wrapper(zaoren)
zaoren()
zaoren()

(4)lol & 消消乐

#lol
def lol():
print('双击lol')
print('选择狂战士')
print('进草丛')
print('崩山击,十字斩')
#开心消消乐
def kxxxl():
print('双击消除')
print('进入下一关')
print('升级')
print('继续玩') #开挂
#关闭外挂
def wrapper(fn):
def inner():
print('开挂')
fn()
print('关闭外挂')
return inner
#lol装饰器
lol=wrapper(lol)
lol()
#
#kxxxl装饰器
kxxxl=wrapper(kxxxl)
kxxxl()
'''
结果:
开挂
双击lol
选择狂战士
进草丛
崩山击,十字斩
关闭外挂
开挂
双击消除
进入下一关
升级
继续玩
关闭外挂
'''

(5)

装饰器传参

def play(username,password):
print('双击lol')
print('登录',username,password)
print('选择狂战士')
print('进草丛')
print('崩山击,十字斩')
return '十字斩刀者'
def xiaoxiaole(qq):
print('登录qq账号')
print('消消乐')
开挂
关闭外挂
在目标函数前和后插入一段新的代码,不改变原来的代码
方法一:(投机版)
def wrapper(fn):   #fn=play
def inner(*args,**kwargs):#无敌传参 聚合接收到的是元组('alex',123)
print('开挂')
fn(*args,**kwargs)
print('关闭外挂')
return '十字斩刀者'
return inner
play=wrapper(play) #play=inner 左边的play代表inner
w=play('alex','')
print(w) #在这里返回的是inner的return xiaoxiaole=wrapper(xiaoxiaole)
xiaoxiaole(11010)
方法二:
def wrapper(fn):   #fn=play
def inner(*args,**kwargs):#无敌传参 聚合接收到的是元组('alex',123)
print('开挂')
s=fn(*args,**kwargs) #这里也有变化
print('关闭外挂')
return s #这里返回的接收的是内部函数的,如果play没有返回值,返回None
return inner
play=wrapper(play) #play=inner 左边的play代表inner
w=play('alex','')
print(w) #在这里返回的是play的return

(6)

通用装饰器写法:(写10遍以上!!!)
#python里面的动态代理
#存在的意义:在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能
#inner相当于代理 def wrapper(fn): #fn是目标函数
def inner(*args,**kwargs): #为了目标函数的传参
'''在执行目标函数之前'''
ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值
'''在执行目标函数之后的操作,可以加if判断等等'''
return ret #目标函数返回值返回,保证函数正常的结束
return inner @wrapper #target_func=wrapper(target_func)
def target_func():
pass
#target_func=wrapper(target_func) #此时上面的fn就是target_func
target_func() #此时执行的是inner
# #注意:不要用打印当成返回值

3.带参数的装饰器

def wrapper_out(flag):              #装饰器本身的参数
def wrapper(fn): #目标函数
def inner(*args,**kwargs): #目标函数执行需要的参数
if flag==True:
print('问问金老板,最近行情怎么样啊?')
ret=fn(*args,**kwargs) #在执行目标函数之前
print('金老板再骗我,恨你')
return ret
else:
ret=fn(*args,**kwargs) #在执行目标函数之前
return ret
return inner
return wrapper
@wrapper_out(True) #先执行wrapper_out(True) 返回一个装饰器wrapper 再和@拼接 @装饰器
# wrapper_out(True)
# yue=wrapper(yue) #左边的yue返回值是inner,右边的yue才是真正的下面的yue
def yue(): #被wrapper装饰
print('走啊,约不?')
yue() #执行yue,这里的yue是指inner,

结果测试:

'''
False:
走啊,约不? True:
问问金老板,最近行情怎么样啊?
走啊,约不?
金老板再骗我,恨你
'''

4.多个装饰器装饰同一个函数

def wrapper1(fn):
def inner(*args, **kwargs):
print("")
ret = fn(*args, **kwargs)
print("")
return ret
return inner def wrapper2(fn):
def inner(*args, **kwargs):
print("")
ret = fn(*args, **kwargs)
print("")
return ret
return inner def wrapper3(fn):
def inner(*args, **kwargs):
print("")
ret = fn(*args, **kwargs)
print("")
return ret
return inner
# 就近原则
@wrapper1
@wrapper2
@wrapper3
def func():
print("我是可怜的func")
func()
#自己总结:把最终要执行的核心语句当成鱼的大刺对称吃鱼原则
# 1 2 3 func 3 2 1

5.装饰器的应用

menu = ("查看", "添加", "修改", "删除", "退出")
flag = False # 没登录 def login():
global flag
username = input("请输入用户名:")
password = input("请输入密码:")
if username == "alex" and password == "":
flag = True
print("登录")
else:
flag = False
print("用户名密码错误") # 登录验证装饰器函数
def login_verify(fn):
def inner(*args, **kwargs):
# 登录校验
while 1:
if flag == True:
ret = fn(*args, **kwargs)
return ret
else:
print('对不起, 您还没有登录')
login()
return inner def chakan():
print("==============================查看") @login_verify
def tianjia():
print("============================添加")
@login_verify
def xiugai():
print("=======================修改")
@login_verify
def shanchu():
print("=========================删除") while 1:
for i in range(len(menu)):
print(i+1, menu[i])
num = input("请输入你要执行的菜单:")
if num == "":
chakan()
elif num == "":
tianjia()
elif num == "":
xiugai()
elif num == "":
shanchu()
elif num == "":
print("程序退出中..........")
exit()
else:
print("输入有误. 请重新选择!")

作业:

1.整理装饰器的形成过程, 背诵装饰器的固定格式

#装饰器通用写法
#存在的意义:在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能
#inner相当于代理 def wrapper(fn): #fn是目标函数
def inner(*args,**kwargs): #为了目标函数的传参
'''在执行目标函数之前的操作'''
ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值
'''在执行目标函数之后的操作,可以加if判断等等'''
return ret #目标函数返回值返回,保证函数正常的结束
return inner
@wrapper #target_func=wrapper(target_func)
def target_func():
# print('1')
pass
#target_func=wrapper(target_func) #此时上面的fn就是target_func
target_func() #此时执行的是inner
#注意:不要用打印当成返回值

2.编写装饰器, 在每次执行被装饰函数之前打印”

每次执行被装饰函数之前都要先经过这里, 这里根据需求添加代码”

def wrapper(fn):     #fn是目标函数
def inner(*args,**kwargs): #为了目标函数的传参
'''在执行目标函数之前的操作'''
ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值 return ret #目标函数返回值返回,保证函数正常的结束
return inner
@wrapper #target_func=wrapper(target_func)
def target_func():
pass
#target_func=wrapper(target_func) #此时上面的fn就是target_func
target_func() #此时执行的是inner
3.编写装饰器, 在每次执行被装饰函数之前打印”
每次执行被装饰函数之后都要经过这里, 这里根据需求添加代码”
def wrapper(fn):     #fn是目标函数
def inner(*args,**kwargs): #为了目标函数的传参 ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值
'''在执行目标函数之后的操作,可以加if判断等等'''
return ret #目标函数返回值返回,保证函数正常的结束
return inner
@wrapper #target_func=wrapper(target_func)
def target_func():
pass
#target_func=wrapper(target_func) #此时上面的fn就是target_func
target_func() #此时执行的是inner

4.编写装饰器, 在每次执行被装饰函数之前让用户输入用户名,

密码, 给用户三次机会, 登录成功之后, 才能访问该函数


def login():
global flag
count=1
#方法一:
# while 1:
# username = input("请输入用户名:")
# password = input("请输入密码:")
# #3次失败,直接离开整个程序
# if username == "alex" and password == "123":
# flag = True #重点:登陆成功之后,改变全局变量为True
# print("登录成功") #登陆成功,直接进入下一步
# break
# else:
# flag = False
# print("用户名密码错误")
# if count==3: #if放在下边和上边是不一样的
# exit()
# count+=1
# else:
# print('您已经输入错误了3次')
#方法二:
# while count<4:
# username = input("请输入用户名:")
# password = input("请输入密码:")
# #3次失败,直接离开整个程序
# if username == "alex" and password == "123":
# flag = True #重点:登陆成功之后,改变全局变量为True
# print("登录成功") #登陆成功,直接进入下一步
# break
# else:
# flag = False
# print("用户名密码错误")
# # if count==3: #if放在下边和上边是不一样的
# # exit()
# count+=1
# print(count)
# else:
# print('您已经输入错误了3次')
# exit()
#方法三:
# for i in range(3):
# username = input("请输入用户名:")
# password = input("请输入密码:")
# #3次失败,直接离开整个程序
# if username == "alex" and password == "123":
# flag = True #重点:登陆成功之后,改变全局变量为True
# print("登录成功") #登陆成功,直接进入下一步
# break
# else:
# flag = False
# print("用户名密码错误")
# # if count==3: #if放在下边和上边是不一样的
# # exit()
# count+=1
# print(count)
# else:
# print('您已经输入错误了3次')
# exit() flag = False # 没登录
def wrapper(fn): #fn是目标函数
def inner(*args, **kwargs):
# 登录校验
while 1:
if flag == True: #问题:函数是怎么走这块的?
ret = fn(*args, **kwargs)
return ret
else:
print('你好,请您登陆!')
login()
return inner
@wrapper #target_func=wrapper(target_func) def target_func():
print('冬瓜你好')
#target_func=wrapper(target_func) #此时上面的fn就是target_func
target_func() #此时执行的是inner

5.编写装饰器, 为多个函数加上认证功能(用户的账户密码来源于文件, 
用户有三次登录的机会), 要求, 如果用户登录成功了, 后续就不需要再次登录了.
def login():
global flag
count=1
#方法一:
s=1
while s:
username = input("请输入用户名:")
password = input("请输入密码:")
#3次失败,直接离开整个程序
with open('info', mode='r', encoding='utf-8') as f:
for i in f.readlines():
t_user,t_pwd=i.split('|')
if username == t_user and password == t_pwd:
flag = True #重点:登陆成功之后,改变全局变量为True
print("登录成功") #登陆成功,直接进入下一步
# break
s=0
else:
flag = False
print("用户名密码错误")
count += 1 #注意应该在这里,把每次错误的数字+1 if count == 4: # if放在下边和上边是不一样的
print('您已经输入错误了3次')
exit()
else:
print('进入下一步') flag = False # 没登录
def wrapper(fn): #fn是目标函数
def inner(*args, **kwargs):
# 登录校验
while 1:
if flag == True: #问题:函数是怎么走这块的?
ret = fn(*args, **kwargs)
return ret
else:
print('你好,请您登陆!')
login()
return inner
@wrapper #target_func=wrapper(target_func) def target_func():
print('冬瓜你好')
#target_func=wrapper(target_func) #此时上面的fn就是target_func
target_func() #此时执行的是inner
6.给每个函数写一个记录日志的功能. 
功能要求: 每一次调用函数之前, 要将函数名称, 事件节点记录到log的日志中.
所需模块:
import time
print(time.strftime(“%Y-%m-%d %H:%M:%S”))
 

巨蟒python全栈开发-第15天 装饰器的更多相关文章

  1. Python 全栈开发五 迭代器 生成器 装饰器

    一.迭代器 迭代协议:对象必须提供一个next方法,执行该方法后会返回迭代的下一项或者抛出Stopiteration异常,终止迭代.切只能往前,不能倒退. 可迭代对象:遵循迭代写一点对象就是可迭代对象 ...

  2. python全栈开发day21-2 几个装饰器总结

    1 @property 将一个方法伪装成属性 2.@propertty @f.setter 设置伪装成方法的属性 3.@propertty @f.deleter 删除一个伪装成方法的属性. class ...

  3. 巨蟒python全栈开发django5:组件&&CBV&FBV&&装饰器&&ORM增删改查

    内容回顾: 补充反向解析 Html:{% url ‘别名’ 参数 %} Views:reverse(‘别名’,args=(参数,)) 模板渲染 变量 {{ 变量名 }} 逻辑相关 {% %} 过滤器: ...

  4. 巨蟒python全栈开发-第22天 内置常用模块1

    一.今日主要内容 1.简单了解模块 你写的每一个py文件都是一个模块 数据结构(队列,栈(重点)) 还有一些我们一直在使用的模块 buildins 内置模块.print,input random 主要 ...

  5. 巨蟒python全栈开发flask3

    首先,我们新建一个项目: 这个时候,我们调用ab函数,可以在所有的模板中使用. 上边是一个特殊装饰器, 1.flask特殊装饰器 下面说几个特殊的装饰器 再请求之前的装饰器 运行: 这个时候,服务端打 ...

  6. 巨蟒python全栈开发flask1

    1.整体把握 (1)路飞学城 - RestAPI 前后端分离开发 Django Vue.js - DRF DjangoRestFromwork - 线上商城的经验 (2)智能玩具 - RestAPI ...

  7. 巨蟒python全栈开发-第10天 函数进阶

    一.今日主要内容总览(重点) 1.动态传参(重点) *,** *: 形参:聚合 位置参数*=>元组 关键字**=>字典 实参:打散 列表,字符串,元组=>* 字典=>** 形参 ...

  8. 巨蟒python全栈开发-第17天 核能来袭-成员

    一.今日主要内容 1.成员 在类中你能写的所有内容都是类的成员 2.变量 (1)实例变量:昨天写的就是实例变量,由对象去访问的变量. (2)类变量(静态变量):此时,这个变量属于类,但是对象也可以访问 ...

  9. 巨蟒python全栈开发flask2

    内容回顾: 上节回顾: Flask .response 三剑客: render_template 模板 redirect 重定向 - URL地址 "" 字符串 HTTPRespon ...

随机推荐

  1. 企业信息系统集成框架(设计思路)C++模式

    设计要求: 1.企业信息系统框架.第三方产品通过接口层进行分层. 2.企业信息系统框架如何自由的继承第三方产品:通过一个抽象类.(软件设计要求:模块要求松,接口要求紧). 设计步骤: 1.报文的接受与 ...

  2. 设置iptables允许ssh、http、ftp服务

    系统环境:centos-6.5 服务器:thinkserver 知识扫盲: NEW:这个包是我们看到的第一个包 ESTABLISHED:一个连接要从NEW变 为ESTABLISHED,只需要接到应答包 ...

  3. SQL数据库相关

    数据库相关知识点 SQL, 对表的理解, 对表的主键, 外键的理解, 视图, 为什么要有视图, 视图有什么功能, 视图与表有什么区别 主键是唯一标识的一条记录,不能重复,不能为空. 表的外键是另一个表 ...

  4. error: Semantic Issue: Interface type cannot be statically allocated

    转自:http://hongmin118.iteye.com/blog/1333524 error: Semantic Issue: Interface type cannot be statical ...

  5. Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '=' 解决方法

    1. 代码 SHOW VARIABLES LIKE 'character_set_%'; 查看一下 显示 +--------------------------+------------------- ...

  6. PL/SQL开发五年工作经验精典实例

    1. minus(差集)与intersect(交集) minus指令是运用在两个SQL语句上.它先找出第一个SQL语句所产生的结果,然后看这些结果有没有在第二个SQL语句的结果中,如果有的话,那这一笔 ...

  7. 八大CMS内容管理系统推荐

    cms系统哪个好 感谢 64320 的投递 时间:2015-03-05 来源:http://www.iisp.com/ztview/ID_16129.html?s=bios 耐思尼克 很多新手站长初次 ...

  8. (译)Getting Started——1.2.2 Desinging a User Interface(设计用户界面)

    ​      用户需要以最简单的方式与应用界面进行交互.应该从用户的角度出发设计页面,使得界面更高效.简捷和直接. storyboard以图形化的方式帮助你设计和实现界面.在设计和实现界面的过程中,你 ...

  9. go 语言学习笔计之结构体

    go 语言中的结构体方法 结构体名称的大小写有着不同的意义: 小写表示不能被别的包访问 package main import "fmt" type Rect struct { w ...

  10. golang模板语法简明教程

    [模板标签] 模板标签用"{{"和"}}"括起来   [注释] {{/* a comment */}} 使用“{{/*”和“*/}}”来包含注释内容   [变量 ...