python装饰器与闭包
闭包= 内部函数+外部环境
def outer(x):
def inner():
print(x+9)
return inner
inner = outer(10)
inner()
正常情况下,L-E-G-B原则,inner()
作为内部函数,处于L级别local
应无法调用上一层级的变量(作用域不同),在满足闭包的情况下,可以直接调用;
什么类型的语言可以使用装饰器?:所有函数可以作为参数传递的语言均可以使用装饰器!!!
装饰器的开放封闭原则:对扩展开放,对修改封闭!!!
源代码为:
def foo():
x = 0
for i in range(10000000):
x += 1
print(x)
foo()
此时需要将源代码扩展,增加计算此函数运行所需时间,不考虑装饰器的情况下:
import time
def foo():
startTime = time.time()
x = 0
for i in range(10000000):
x += 1
print(x)
endTime = time.time()
print("useTime:%s"%(endTime-startTime))
foo()
或:
import time
def foo():
x = 0
for i in range(10000000):
x += 1
print(x)
def show_time(f):
startTime = time.time()
f()
endTime = time.time()
print("useTime:%s" % (endTime - startTime))
show_time(foo)
在各大公司,当一个函数被大量调用后,无法得知,此函数是否被其他人员调用,因此,对于已经实现的函数功能,不可对源码进行更改,即“开放封闭原则“,故需要使用到装饰器:
import time
def foo():
x = 0
for i in range(10000000):
x += 1
print(x)
def show_time(f):
def inner():
startTime = time.time()
f()
endTime = time.time()
print("useTime:%s" % (endTime - startTime))
return inner
foo = show_time(foo)
foo()
使用闭包,内部函数调用外部变量,再将函数赋值,按原函数调用时,就会执行闭包中的内部函数,以此调用原函数,达到不改变原函数与调用方式,做到扩展原来功能的要求。
python默认将foo = show_time(foo)
代码使用@
表示:
import time
def show_time(f):
def inner():
startTime = time.time()
f()
endTime = time.time()
print("useTime:%s" % (endTime - startTime))
return inner
@show_time #foo = show_time(foo)
def foo():
x = 0
for i in range(10000000):
x += 1
print(x)
foo()
装饰器的作用即为,在引用函数时,将原调用函数执行红色部分变动为执行蓝色部分!
补充一段简单的装饰器代码,仅供参考:
loginStatus = False
loginStatus2 = False
def login(choose_type):
def type(func):
if choose_type == 1:
def inner():
global loginStatus
if loginStatus == False:
name = input("请输入账号:")
passwd = input("请输入密码:")
f = open("login_list", 'r', encoding='utf8')
data1 = f.read()
data2 = eval(data1)
f.close()
if name in data2:
if passwd == data2[name]:
print("welcome".center(40,"#"))
loginStatus = True
func()
else:
print("no such name or password")
else:
print("no such name or password")
else:
func()
return inner
elif choose_type == 0:
def inner():
global loginStatus2
if loginStatus2 == False:
name = input("请输入账号:")
passwd = input("请输入密码:")
data2 = {"xin":"123456"}
if name in data2:
if passwd == data2[name]:
print("welcome".center(40, "#"))
loginStatus2 = True
func()
else:
print("no such name or password")
else:
print("no such name or password")
else:
func()
return inner
return type
@login(1)
def home():
print("welcome to home")
@login(0)
def finance():
print("welcome to finance")
@login(1)
def book():
print("welcome to book")
while True:
print("""
1、home
2、finance
3、book
""")
choose = input(">>>")
if choose.isdigit() and int(choose)>0 and int(choose)<4:
choose = int(choose)
if choose == 1:
home()
elif choose == 2:
finance()
elif choose == 3:
book()
else:
print("no such page")
-
补充知识点:有关原函数的元信息查看。
# 对于一般装饰器使用,在执行过程中无法调用原函数的元信息‘__doc__,__name__,__dict__ 等’ import time def show_time(f): def inner(*args): ''' *args : 装饰器引入参数 ''' startTime = time.time() f(*args) endTime = time.time() print("useTime:%s" % (endTime - startTime)) return inner @show_time #foo = show_time(foo) def foo(a): ''' a : aaaaa ''' x = 0 print(a) for i in range(10000000): x += 1 print(x) foo('22') # 22 10000000 useTime:0.4469478130340576 # 此处查看__doc__调用的是装饰器的内置函数的元信息 故显示 *args : 装饰器引入参数 print(foo.__doc__) # *args : 装饰器引入参数
以下做法可以使装饰器也可查阅原函数的元信息
import time import functools def show_time(f): # 引入内置函数 functools.wraps 将调用装饰器的函数作为参数传入,即可复制调用装饰器的原函数的元信息,此时装饰器可查看原函数元信息 @functools.wraps(f) def inner(*args): ''' *args : 装饰器引入参数 ''' startTime = time.time() f(*args) endTime = time.time() print("useTime:%s" % (endTime - startTime)) return inner @show_time #foo = show_time(foo) def foo(a): ''' a : foo函数的传入参数 ''' x = 0 print(a) for i in range(10000000): x += 1 print(x) foo('22') # 22 10000000 useTime:0.4469478130340576 # 此处显示的为装饰器复制的原函数的元信息,起到便捷作用,提升代码的可读性 print(foo.__doc__) # a : foo函数的传入参数