装饰器:
闭包的升级,在开发上的应用例如判断用户的登录状态。修改丰富已经写好的函数。
回顾:以函数作为参数(也是装饰器的基础):
def test():
print("test")
t = test
t()
# test
print(f)
# <function test at 0x000002BA5B9F7678>
print(test)
# <function test at 0x000002BA5B9F7678>
把test的地址赋值给了t,t加()就相当于test(),具体的过程在上一篇笔记闭包的介绍里。
下面介绍装饰器:
特点:
1.函数A是作为参数出现的。
2.有闭包的特点出现。
具体使用情景:当一个函数已经定义完成,但是想丰富它的内容时。
但是问题来了,我们怎么做才能实现这些功能呢?
我们可以尝试:
1.直接修改原来的函数。
2.重新定义一个函数调用原来的函数,并且加上新的内容。
比如下列代码:
def house():
print("毛坯房")
def house1():
house()
print("刷漆")
print("铺地板")
house()
这两种方法都不是可行的,因为在修改的时候,会改变调用这个函数位置的代码,如果那里的代码已经完成,修改会很耗费时间。
这时候我们就要引出装饰器了,它可以在不改变函数名的情况下对函数进行装饰丰富。
定义一个装饰器:
def decorate(func):
a = 100
print("wrapper外层")
def wrapper():
func()
print("1111")
print("2222")
print("wrapper加载完成")
return wrapper
# 使用装饰器
# @后加装饰器函数表示使用这个函数作为装饰函数。
@decorate
def house():
print("毛坯房")
# wrapper外层
# wrapper加载完成
注意:这里并没有调用house函数,但是却执行了decorate里的一些步骤。
下面说明一下当执行到@decorate之后底层执行的工作:
1.确定house为被装饰函数。
2.将house作为被装饰函数作为参数给decorate函数。
3.调用decorate里的代码,注意里面定义的函数(例如wrapper)不会执行。
4.然后再用house接收返回值wrapper。
def decorate(func):
a = 100
print("wrapper外层")
def wrapper():
func()
print("1111")
print("2222")
print("wrapper加载完成")
return wrapper
@decorate
def house():
print("毛坯房")
print(house)
# <function decorate.<locals>.wrapper at 0x00000236C3D1FC18>
可以看出wrapper和house的地址是一样的。
装饰器decorate并没有改变原函数的名字和结构,但是对原函数的功能进行了改变,但是此时的house执行的代码和原来的不一样了,执行的是返回的wrapper区域里的代码。当然,wrapper里的代码是经过装饰器decorate修改加工的。
带参数的装饰器:
def decorate(func):
a = 100
print("wrapper外层")
def wrapper():
func(x)
print(x)
print("1111")
print("2222")
@decorate
def house(n):
print("毛坯房")
house(5)
还是一上面的代码为例。因为在装饰之后house的地址指向的是wrapper的地址,如果想要装饰,wrapper和house还有decorate里的参数func使用时都必须要有参数,或者同时没有。不然的话在传递参数的时候会报错。
此外,还有一种万能的装饰器,就是把wrapper和func中的参数变成可变参数。
def decorate(func):
a = 100
def wrapper(*x):
func(*x)
return wrapper
@decorate
def house(x):
print("house函数")
for i in x:
print(i)
print("house函数end")
num = [1,2,3]
house(num)
# house函数
# 1
# 2
# 3
# house函数end
在这里func里的变量也要加 * ,因为不加 * 表示的是一个列表,列表不拆包的时候只能作为一个形参传递进去。
注意当有多个装饰器的时候先装饰离函数最近的。
装饰器的一个应用:付款(非常简陋):
import time
users = dict() # 定义一个字典。
# 定义初始的用户名密码。
users["1234"] = "123456"
users["12345"] = "1234567"
islogin = False # 判断是否登录,默认是没有登录的。
# 登录页面。
def login():
username = input("输入用户名:")
password = input("输入密码:")
if users.get(username) == password:
return True
else:
return False
# 定义一个装饰器,进行付款验证。
def login_required(func):
def wrapper(*args,**kwargs):
global islogin
while islogin == False:
# 跳转登录页面。
print("未登录无法付款!")
islogin = login()
func(*args,**kwargs)
return wrapper
# 付款函数。
@login_required
def pay(money):
print("正在付款中,付款金额是:{}元".format(money))
print("付款中....")
time.sleep(2)
print("付款成功!")
pay(100000000)
# 未登录无法付款!
# 输入用户名:>? 1234
# 输入密码:>? 123456
# 正在付款中,付款金额是:100000000元
# 付款中....
# 付款成功!
pay(8000)
# 正在付款中,付款金额是:8000元
# 付款中....
# 付款成功!
这里可以很好地体现出装饰器的作用,代码一定要多实践,写完之后我就明白了为什么要设置装饰器这个东西了。装饰函数的时候可以用在很多地方,比如说这个登录页面,如果只是单纯地在pay等使用它的函数上增加代码,会造成代码的重复,使程序就会变得非常复杂。比如说当我们要修改登陆验证代码的时候。会在各个地方修改,非常不好找。
作用域搜索顺序:LEGB
L:local本地,局部变量。
E:encloseing嵌套。
G:global全局变量。
B:built-in内置的。
b = 4
def f():
a = 1
def f1():
a = 3
print(a)
print(b)
print(max)
f1()
f()
# 3
# 4
# <built-in function max>
不知不觉已经学了123集了,希望能坚持下去,做自己热爱的事业是人生最幸福的事情。