闭包函数,装饰器
目录
闭包函数
什么是闭包函数
闭包函数把 闭包函数内的变量 + 闭包函数内部的函数, 这两者包裹起来,然后通过返回值的形式返回出来。
- 定义在函数的内函数
- 该函数体代码包含对该函数外层作用域中变量的引用
- 函数外层指的不是全局作用域
def outter():
x = 10
def inner():
print(x)
return inner
f = outter() # f=inner
f()
print(f)
# 打印结果:
10
<function outter.<locals>.inner at 0x00000201011A7840>
上述代码中,f是一个全局的名字,但f拿到了inner的内存地址。将一个定义在内部的函数返回出来,在全局拿到f,这个f是全局变量,这样就打破了函数的层级限制,能在任意位置使用内部的函数
闭包函数的应用
以参数的方式传值
import requests
def get(url):
response = requests.get(url)
print(response.text)
get('https://www.baidu.com')
这里写了一个爬虫函数,爬取百度的首页。但这样的问题就是每次想爬百度,或者其他网站都要传一堆网址,比较麻烦,所以可以用闭包函数解决。
传值另一方式: 包给函数
import requests
def spider(url):
def get():
response = requests.get(url)
print(response.text)
return get
baidu = spider('https://www.baidu.com')
baidu()
taobao = spider('https://www.taobao.com')
taobao()
这样就很方便,以后调baidu,直接baidu()就行了
装饰器
什么是装饰器
装饰器就是 为需要装饰的函数新增了一个额外的功能,装饰器的本质就是一个 给函数增加功能的函数。
为什么要装饰器
装饰器,增加功能需要注意以下几点:
- 不改变原函数的原代码
- 不改变原函数的调用方式
使用无参装饰器
import time
def index():
'''被装饰函数'''
time.sleep(1)
print('welcome to index')
index()
需要为上面的函数新增加一个功能,能够统计函数运行的时间
在原代码上修改
import time
def index():
start = time.time()
time.sleep(1)
print('welcome to index')
end = time.time()
print(f'run time is {end - start}')
index()
这样就违反了不能修改原代码这一原则
import time
def index():
time.sleep(1)
print('welcome to index')
start = time.time()
index()
end = time.time()
print(f'run time is {end - start}')
这样写就不是装饰器,因为装饰器是一个函数
利用函数传参方式
import time
def index():
'''被装饰函数'''
time.sleep(1)
print('welcome to index')
def time_count(func):
start = time.time()
func()
end = time.time()
print(f'run time is {end - start}')
time_count(index)
虽然实现了,但改变了函数调用方式
利用闭包
import time
def index():
'''被装饰函数'''
time.sleep(1)
print('welcome to index')
def deco(func): # func = index 最初的index
def time_count():
start = time.time()
func()
end = time.time()
print(f'run time is {end - start}')
return time_count
# f = deco(index)
index = deco(index) # index = time_count
index()
这样就简单实现了一个装饰器函数,调用index不是调用最初的index了,而是调用time_count函数,但用户不知道,看起来就和原来使用一样
装饰器完善
上述的装饰器,最后调用index()的时候,其实是在调用time_count(),因此如果原始的index()有返回值的时候,time_count()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和time_count()方法的返回值。
import time
def index():
'''被装饰函数'''
time.sleep(1)
print('welcome to index')
return 1234
def deco(func):
def time_count():
start = time.time()
res = func()
end = time.time()
print(f'run time is {end - start}')
return res
return time_count
# index = deco(index) # index = time_count
# index()
res = index()
print(res)
给原始index传参
import time
def index(x):
'''被装饰函数'''
time.sleep(1)
print('welcome to index')
return 1234
def deco(func):
def time_count(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs)
end = time.time()
print(f'run time is {end - start}')
return res
return time_count
index = deco(index) # index = time_count
index(10)
使用装饰器语法糖
import time
def deco(func):
def time_count(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(f'run time is {end - start}')
return res
return time_count
@deco # 这里就相当于 index = deco(index)
def index(x):
'''被装饰函数'''
time.sleep(1)
print('welcome to index')
return 1234
index(10)
装饰器模板
def deco(func):
def wrapper(*args,**kwargs):
# 这里加功能
res = func(*args,**kwargs)
return res
return wrapper
装饰器小练习
# 写一个登录装饰器,装饰猜年龄,登录了才能玩猜年龄
username_list = []
def guess(age):
print('welcome to guess age')
age_inp = input('请猜年龄').strip()
age_inp = int(age_inp)
if age_inp == age:
print('bingo')
elif age_inp < age:
print('猜小了')
else:
print('猜大了')
def login(func):
def wrapper(*args,**kwargs):
if username_list:
print('已登录,请勿重复登录')
res = func(*args, **kwargs)
return res
username_inp = input('请输入用户名:').strip()
pwd_inp = input('请输入密码:').strip()
with open('user_info.txt', 'r', encoding='utf-8') as fr:
for user_info in fr:
user_info = user_info.strip()
username, pwd = user_info.split(':')
if username_inp == username and pwd_inp == pwd:
print('登录成功')
username_list.append(username_inp)
res = func(*args, **kwargs)
return res
else:
print('登录失败')
res = func(*args,**kwargs)
return res
return wrapper
guess = login(guess)
guess(19)
有参装饰器
import time
def outter(age):
def deco(func):
def wrapper(*args,**kwargs):
if age >= 18:
print('成年了')
else:
print('未成年')
start = time.time()
res = func(*args,**kwargs)
end = time.time()
print(f'run time is {end - start}')
return res
return wrapper
return deco
@outter(19) # 相当于 deco = outter(19) index = deco(index)
def index():
'''被装饰函数'''
time.sleep(1)
print('welcome to index')
index()