一.闭包函数:内部函数包含对外部作用域而非全局作用域的引用
闭:封闭,指的是该函数是定义一个函数内部的函数
包:该内部函数包含对外层函数名字的引用
提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来
二.闭包的意义与应用
1.闭包的意义:返回的函数对象,不仅仅是一个函数对象,在函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
2.应用领域:延迟计算(原来我们是传参,现在我们是包起来)
def counter():
n = 0
def incr():
nonlocal n
x = n
n += 1
return x
return incr
c = counter()
print(c()) #0
print(c()) #1
print(c()) #2
print(c.__closure__[0].cell_contents) # 查看闭包的元素
from urllib.request import urlopen
def index(url):
def get():
return urlopen(url).read()
return get
baidu = index('http://www.baidu.com')
print(baidu().decode('utf-8'))
3.函数传值的两种方式(闭包的应用)
#1.直接以参数的形式传入
def foo(name):
print("hello %s" %name)
foo("petrus")
#2.闭包函数
def outer(name):
def foo():
print("hello %s" %name)
return foo
f=outer("egon")
f()
三.装饰器(闭包的应用)
1.什么是装饰器
装饰器本身可以是任意可调用的对象-->函数
被装饰的对象也可以是任意可调用的对象-->函数
目标:写一个函数来为另外一个函数添加新功能
2.为何要用装饰器
开放封闭原则:软件一旦上线就应该对修改封闭,对扩展开放
对修改封闭:
1)不能修改功能的源代码
2)也不能修改功能的调用方式
对扩展开放:
可以为原有的功能添加新的功能
装饰器就是要在不修改功能源代码以及调用方式的前提下为原功能添加额外的新功能
3.如何用装饰器
import time
def index():
print("welcome to china")
time.sleep(5)
def outer(func):
# func=最原始的那个index的内存地址
def wrapper():
start=time.time()
func() #最原始的那个index的内存地址
stop=time.time()
print("run time is %s" %(stop-start))
return wrapper
index=outer(index) #index=outer(最原始那个index的内地址) #index=wrapper函数的内地址
index()
四.装饰器的使用
1.无参装饰器
#无参装饰器的模板
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
------------------------------------------------------------------------------------
import time
from functools import wraps
def timer(func): # func=最原始的那个index的内存地址
@wraps(func)
def wrapper(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs) #最原始的那个index的内存地址
stop=time.time()
print("run time is %s" %(stop-start))
return res
return wrapper
@timer #index=timmer(index) #index=timmer(最原始那个index的内地址) #index=wrapper函数的内地址
def index():
"""这是index功能"""
print("welcome to index page")
time.sleep(5)
return 123
@timer #home=timmer(home) #home=timmer(最原始那个home的内地址) #home=wrapper函数的内地址
def home(name):
"""这是home功能"""
print("welcome %s to home page" %name)
time.sleep(6)
index()
home("petrus")
2.有参装饰器
import time
user_info = {'current_user': None}
def auth2(engine="file"):
def auth(func):
def wrapper(*args, **kwargs):
if user_info["current_user"] is not None:
res = func(*args, **kwargs)
return res
inp_user = input("username>>>:").strip()
inp_pwd = input("password>>>:").strip()
if engine == "file":
print("基于文件的认证")
if inp_user == "petrus" and inp_pwd == "123":
user_info["current_user"] = inp_user
print("login successful")
res = func(*args, **kwargs)
return res
else:
print("user or password error")
elif engine == "mysql":
print('基于mysql数据的认证')
elif engine == "ldap":
print('基于ldap的认证')
else:
print("无法识别认证源")
return wrapper
return auth
@auth2("file") #@auth ------>index=auth(index) index=auth(最原始那个index的内地址) index=wrapper
def index():
"""这是index功能"""
print("welcome to index page")
time.sleep(5)
return 123
@auth2("mysql") #@auth ------->home=auth(home) home=auth(最原始那个home的内地址) home=wrapper
def home(name):
"""这是home功能"""
print("welcome %s to home page" %name)
time.sleep(6)
index() #wrapper()
home('petrus')
3. 装饰器的叠加
加载装饰器就是将原函数名偷梁换柱成了装饰器最内层那个wrapper函数
在加载完毕后,调用原函数其实就是在调用wrapper函数
当一个被装饰的对象同时叠加多个装饰器时:装饰器的加载顺序是自下而上,装饰器内wrapper函数的执行顺序是:自上而下
import time
def timer(func): #func=最原始的 index内存地址
def wrapper1(*args,**kwargs):
print("==========================wrapper1运行了")
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print("run time is %s" %(stop-start))
return res
return wrapper1
def auth(engine="file"):
def xxx(func): #func=wrapper1的内存地址
def wrapper2(*args,**kwargs):
print("===========================wrapper2运行了")
name=input("username>>>>:").strip()
pwd=input("password>>>:").strip()
if engine=="file":
print("基于文件的认证")
if name=="petrus" and pwd=="123":
print("login successful")
res=func(*args,**kwargs)
return res
else:
print("用户名或密码错误")
elif engine=="mysql":
print("基于数据库的认证")
elif engine=="ldap":
print("基于ldap的认证")
else:
print("未知的认证来源")
return wrapper2
return xxx
@auth(engine="file") #@xxx ----> index=xxx(wrapper1) ---- > index=wrapper2的内存地址
@timer # index=timer(最原始的index内存地址) ---------> index=wrapper1的内存地址
def index():
print("welcome to index page")
time.sleep(2)
index() #这里的index实际上是wrapper2的内存地址
"""
打印结果:
===========================wrapper2运行了
username>>>>:petrus
password>>>:123
基于文件的认证
login successful
==========================wrapper1运行了
welcome to index page
run time is 2.0001144409179688
"""
五.关于装饰器的语法糖wraps装饰器的说明
from functools import wraps
def deco(func):
@wraps(func) #加在最内层函数正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper
@deco
def index():
'''哈哈哈哈'''
print('from index')
print(index.__doc__)