前言
函数嵌套,闭包,装饰器
一、函数嵌套
- 函数像变量一样有其定义域,在执行的时候优先在自己作用域中寻找,找不到则向上的作用域查找
- 函数可以嵌套
# 全局作用域定义
def my_function():
print("中国人民")
def execute():
print("执行")
my_function() # 本定义域没有,向上一级作用域查找该函数并执行
print("执行完")
execute()
def my_function(): # 覆盖上一个同名函数
print(9999)
my_function()
比较以下2个代码块不同
name = "武大"
def fun1():
print(name)
def my_fun():
name = "func_name"
fun1()
my_fun() # 输出武大
- 注意作用域和向上一级作用域查找
name = "武大"
def my_fun():
name = "func_name"
def fun1():
print(name)
fun1()
my_fun() # 输出func_name
二、闭包
- 闭包是使用函数嵌套方法,将数据封装在一个包,或称作区域,需要使用的时候再取出来。
多线程背包下载应用
# 使用线程池
from concurrent.futures.thread import ThreadPoolExecutor
import requests
# 下载函数
def download_video(url):
result = requests.get(
url=url,
headers={
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS"
}
)
return result.content
# 闭包
def outer_bag(file_name):
def write_file(response):
content = response.result()
with open(file_name, mode='wb') as file_object:
file_object.write(content)
return write_file
POOL = ThreadPoolExecutor(8)
pic_dic = [
("人物.jpg", "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F013db45e18b22da80120a8951c093b.jpg%403000w_1l_0o_100sh.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646708589&t=53139d305d7b57a0b942bd2f7d04e4f6"),
("海边.jpg", "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fphotoblog%2F1503%2F17%2Fc14%2F4005236_4005236_1426584510803_mthumb.jpg&refer=http%3A%2F%2Fimg.pconline.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646708615&t=99d89fc8f1c8f7707b7eda3c6ebb1f71"),
("山峰.jpg", "https://pics1.baidu.com/feed/2fdda3cc7cd98d1056e64139c7617d0b7bec9068.jpeg?token=584cb35be2acb7c6918b59dc65a4bf42&s=1F84EC4CC2F1F2645EA940800300A09A")
]
for item in pic_dic:
future = POOL.submit(download_video, url=item[1])
future.add_done_callback(outer_bag(item[0]))
POOL.shutdown()
三、装饰器
- 基于背包的原理,在不改变原函数的情况下,对原函数的功能进行扩展
- 在原函数上使用@装饰器,相当于:原函数=装饰器(原函数)
- 适合在批量函数中使用
- 将原函数封装在闭包中,然后将函数赋值成一个新的函数
代码如下(示例):
def fuc_decorator(origin):
def inner(*args, **kwargs):
# 执行前需要添加的语句
print('前')
result = origin(*args, **kwargs) # 调用原来的func函数
# 执行后需要添加的语句
print('前')
return result
return inner
# 装饰器相当于my_function=fuc_decorator(my_function)
@fuc_decorator
def my_function(*args, **kwargs):
print('我是my_function')
print(args)
my_function(1,2)
应用
- 在每个网页视图中需要判断有没有经过授权时,用装饰器来判断
from flask import Flask
app = Flask(__name__)
def auth(func):
def inner(*args, **kwargs):
# 判断如果用户是否已经登录,如果未登录则自动跳转到登录页面
return func(*args, **kwargs)
return inner
# 判断如果用户是否已经登录,如果未登录则自动跳转到登录页面
@auth
def index():
return "官方主页"
def person_info():
return "个人中心"
def load():
return "下载中心"
def login():
return "登录"
app.add_url_rule("/index/", view_func=index)
app.add_url_rule("/info/", view_func=person_info)
app.add_url_rule("/login/", view_func=load)
app.run()
装饰器实际上就是将原函数伪装为其他的函数,然后再此函数中再去调用原函数,实质上是inner函数,所以__name__,__doc__都返回的值是inner函数的
def outer(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
@outer
def my_fuc():
pass
my_fuc()
# __name__属性是输出函数的名字,装饰器后的函数名字其实是inner
print(my_fuc.__name__) # inner
- 加入@functools.wraps(func)后可以伪装得更像,导出的名字和注释都是自己的
import functools
#导入这个包中的wraps后 __name__,__doc__返回的都是自己的名字,而不是装饰器的闭包函数名
def outer(func):
@functools.wraps(func)
def inner(*args, **kwargs):
'''inner的注释'''
return func(*args, **kwargs)
return inner
@outer
def my_fuc():
'''my_fuc的注释'''
pass
my_fuc()
# __name__属性是输出函数的名字,__doc__打印注释
print(my_fuc.__name__) # 自己的名字,而不是装饰器后的inner
print(my_fuc.__doc__)