12python闭包和装饰器


前言

函数嵌套,闭包,装饰器


一、函数嵌套

  • 函数像变量一样有其定义域,在执行的时候优先在自己作用域中寻找,找不到则向上的作用域查找
  • 函数可以嵌套
# 全局作用域定义
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__)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值