python---闭包

2023-11-01

1.闭包理解

  1. 闭包定义:在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包

2.必报的构成条件:

  • 在函数嵌套(函数里面在定义函数)的前提下

  • 内部函数使用了外部函数的变量(还包括外部函数的参数)

  • 外部函数返回了内部函数

3.闭包书写步骤:

  • 定义外部函数

  • 定义外部函数,在内部函数中使用外部函数的变量

  • 外部函数返回内部函数的地址

代码需求:
一个初始值 num
对 num 的基础上进行 加法运算
# 定义内部函数:
def outer(num):
    # 2.定义内部函数,在内部函数中使用外部函数的变量
    def inner(num1):
        print(num + num1)

    # 3.外部函数返回内部函数的地址
    return inner  # 函数名字就是函数地址


if __name__ == '__main__':
    # 创建闭包实例
    func = outer(100)  # 此时func相当于是inner
    # 调用闭包
    func(10)  # 此时调用inner函数,保存的num值为100
# 可以创建多个闭包实例,不同的闭包实例之间,不会相互影响

2.闭包的使用

  1. 案例:根据配置信息使用闭包实现不同人的对话信息,例如对话:

张三:到北京了吗?

李四:已经到了,放心吧。

  1. 实现步骤说明

  • 定义外部函数接受不同的配置信息参数,参数是人名

  • 定义内部函数接受对话信息参数

  • 在内部函数里面把配置信息和对话信息进行拼接输出

def outer(name):
    # 定义内部函数,参数是 说话的信息
    print(f'{name}:到北京了吗?')

    def inner(name1):
        # 内部函数中,将name和info进行拼接输出
        print(f'{name1}:已经到了,放心吧。')

    # 外部函数返回内部函数的地址
    return inner


# 创建闭包实例
if __name__ == '__main__':
    func = outer('张三')
    func('李四')

注意点:由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。

3.闭包修改外部函数变量(理解)

函数内部想要修改全局变量,使用global关键字
在闭包函数内部,想要修改外部函数的局部变量,需要使用nonlocal关键字
def outer():
    num = 10

    def inner():
        # num = 100  # 不是修改外部变量的值,重新定义的局部变量
        nonlocal num  # 声明使用外部变量 num 不重新定义
        num = 100

    print(f'调用inner之前:{num}')
    inner()
    print(f'调用inner之后:{num}')
    return inner


func = outer()
func()

4.装饰器(理解)

装饰器的功能:就是给已有函数添加新的功能
           1.不修改已有函数的1源代码
           2.不修改已有函数的调用方式
           3.给函数添加功能
 
装饰器本质就是一个闭包函数,只不过比较特殊
1.定义外层函数(要求参数只有一个,类型是函数类型,调用时传参传递的是原函数)
2.定义内层函数,在内层函数中,书写新的功能,并在合适的时机调用原函数
3.返回内部函数的地址
 
装饰器的书写方法: 新的功能和原函数进行对比,查看需要的新的功能,将新功能书写在inner的内层函数中
案例需求:
原函数: comment()  一个评论功能
新的需求:在评论之前,检查是否登录
# -------------------装饰器-----------------
def login_check(fn):
    def inner():
        # 书写新的功能,使用print进行模拟
        print('登录验证......')
        # 新的功能书写完成之后,调用原函数
        fn()

    return inner


# 装饰器的语法糖格式,
@login_check  # comment =login_check(comment)
def comment():
    # 使用print输出模拟评论功能
    print('进行评论检查......')


# 在调用之前创建闭包实例
# func = login_check(comment)
comment = login_check(comment)
if __name__ == '__main__':
    comment()

5.装饰器语法糖格式替换时机

def func():
    pass
 
 
func()
需求:统计函数执行所消耗的时间(新)
1.执行函数前记录当前时间
2.执行函数
3.函数执行结束之后,再次记录当前时间(新)
两次的时间差就是就是函数执行的时间
-----装饰器语法糖格式替换时机-----

import time


# 定义装饰器函数:
def calc_time(fn):
    def inner():
        # 记录当前时间
        start = time.time()  # 记录当前时间的秒数
        fn()
        end = time.time()
        print(f'函数耗时{end - start}')

    return inner


# 定义原函数
@calc_time
def func():
    for i in range(10):
        print(i)
        time.sleep(0.3)
    print('函数执行')


if __name__ == '__main__':
    func()

6.装饰器输出日志信息

需求:
   def func1():
       pass
   def func2():
       pass
在每次进入函数时:输出 func1 enter......
函数执行结束之后,输出 func leave.....

分析步骤:
1.函数执行前,输出func1 enter....
2.执行函数
3.执行结束, 输出 func1 leave.....
# 定义原函数:
def logger(fn):
    def inner(*args, **kwargs):
        print(f'{fn.__name__} enter....')
        fn(*args, **kwargs)
        print(f'{fn.__name__} leave....')

    return inner


@logger
def comment1():
    print('评论功能:')


@logger
def func(num):
    print(num)


if __name__ == '__main__':
    comment1()
    func(10)

11.装饰带返回值的函数

不管原函数有没有返回值,装饰器的内部函数都应该将fn函数的返回值进行返回

  1. 如果原函数有返回值,返回的就是原函数的返回值

  1. 如果没有返回的是None

#     func(10)
# ----装饰带返回值的函数---
def logger(fn):
    def inner(*args, **kwargs):
        print(f'{fn.__name__} enter....')
        result=fn(*args, **kwargs)
        print(f'{fn.__name__} leave....')
        # 函数没有书写返回值,默认返回None
        return result

    return inner


@logger
def func(into):
    return into


@logger
def my_sum(a, b):
    return a + b


if __name__ == '__main__':
    print(func('hello'))
    print(func((3, 6)))

12.通用装饰器

def decorate(fn):
    def inner(*args,**kwargs):
          ...
        result=fn(*args,**kwargs)
        return result
     return inner

13.多个装饰器装饰同一个函数

def comment(info):
   return info
 
 1.书写一个装饰器 给原函数的返回值加上p 标签
<p>返回值</p>
2.书写一个装饰器,给 原函数加上 div标签
<div> 返回值 </div>
# ---多个装饰器装饰同一个函数----
def make_p(fn):
    def inner(info):
        result = fn(info)
        return '<p>' + result + '</p>'
    return inner
#
#
# @make_p
# def comment(info):
#     return info
#
#
# if __name__ == '__main__':
#     print(comment('hello world'))

def make_div(fn):
    def inner(info):
        result = fn(info)
        return '<div>' + result + '</div>'

    return inner
# 多个装饰器装饰同一个函数,装饰顺序是就近原则,谁离原函数近,就先装饰谁
# 1.comment =make_p(comment)
# 2.comment =make_div(comment)
@make_div
@make_p
def comment(info):
    return info


if __name__ == '__main__':
    print(comment('hello world!'))

14.带参数的装饰器

# 装饰器  make_tag


@make_tag('div')
@make_tag('p')
def comment():
    pass

1.当代码执行到第4行,@make_tag('div')
 
 
def make_tag(tag):
   返回一个装饰器
def make_tag(tag):
    # 返回一个装饰器
    def decorate(fn):
        def inner(*args, **kwargs):
            result = fn(*args, **kwargs)
            return f'<> {tag}>{result}</{tag}'

        return inner

    return decorate  # 返回装饰器

# 1.先进行函数调用,返回装饰器
# 2.对原函数进行装饰
@make_tag('aini')
@make_tag('div')
@make_tag('p')
def comment(info):
    return info


if __name__ == '__main__':
    print(comment('hello world'))

15.题目训练加强

1.闭包的特点是什么?

1.外部函数中定义了一个内部函数
2.外部函数总是返回内部函数的引用
3.内部函数可以使用外部函数提供的环境变量

2.创建一个闭包,实现统计函数执行的次数功能

有如下调用闭包函数的代码

f=func_count()
f()
f()
f()
def func_count():
    num = 0

    def inner():
        nonlocal num
        num += 1
        print('hello world')
        print(f'共执行次数{num}')

    return inner


if __name__ == '__main__':
    f = func_count()
    # 调用闭包
    f()
    f()
    f()

3.实现装饰器,实现对函数执行时间进行计算的能力

import time


def outer(fn):
    def inner():
        start = time.time()
        fn()
        end = time.time()
        print(f'{end - start}')

    return inner


@outer
def func():
    for i in range(10):
        print(i)
        time.sleep(0.3)


if __name__ == '__main__':
    func()

4.一个函数,返回一个字符串,使用装饰器实现对这个字符串添加后缀.txt

def func(fn):
    def inner(info):
        result = fn(info)
        return result + '.txt'

    return inner


@func
def comment(into):
    return into


if __name__ == '__main__':
    print(comment('hello world'))

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python---闭包 的相关文章

随机推荐

  • innovus中常用命令整理

    restoreDesign load 之前的db list property type 列举出相应的属性 get property 得到相应的object的属性 get pin 获取pin get port 获取port ecoRoute
  • 2023开学礼山东财经大学《乡村振兴战略下传统村落文化旅游设计》许少辉新财经图书馆

    2023开学礼山东财经大学 乡村振兴战略下传统村落文化旅游设计 许少辉新财经图书馆
  • adworld攻防世界 reverse asong

    asong 攻防世界 reverse 进阶区 asong 题目文件 https www jianguoyun com p DQ3g5b4QiNbmBxjX fQC 访问密码 AgV9Sh 主要是集中我们常见的处理方式的整合 注意一个对于ou
  • 进程间通信---管道通信

    进程间通信为什么有那么多不同的方法 资源的不同 所以通信的方式不同 想要获取管道资源 就需要用管道来通信 想要获取消息队列资源 就需要用消息队列来通信 如上所示 一个进程就是一个PCB PCB中的file struct有三个默认文件描述符
  • 【转】 如何提高自己的acm个人能力

    转载自 简单de数字 最终编辑 fading code by zfy0701 本来以为HNU的huicpc035和我一样退役了 后来听说他组成了新的footman队 于是又关注了下他 035体现了两个我觉得非常重要的品质 1 刻苦的训练 2
  • vmtools的安装和使用

    介绍 vmtools工具是在虚拟系统和主机系统进行共享文件夹的工具 1 用root用户登录CentOS后删除桌面的光驱 2 点击菜单栏的虚拟机 gt 安装VMwareTools 3 安装结果如下所示 4 打开VMwareTools 复制VM
  • 【python】Something is wrong with the numpy installation

    2020年2月5日 0次阅读 共448个字 0条评论 0人点赞 QueenDekimZ COCO API windows下安装COCO API时 python setup py build ext install 出现报错 ImportEr
  • Unity中UI框架的使用3-主界面中的弹窗和关闭

    效果图 在主页面点击排位赛按钮 就会弹出图2中的一个弹窗 再点击弹窗右上角的关闭按钮 就会关闭弹窗 回到图3的效果 方法 1 将PopUp这个面板添加到UIPanelType cs文件中 并且将其名称和路径添加到UIPanelType js
  • Python高级函数1:使用 map()、reduce()、filter()、zip() 和 enumerate() 简化代码

    Python高级函数1 使用 map reduce filter zip和 enumerate 简化代码 1 原理 1 1 map 函数 1 2 reduce 函数 1 3 filter 函数 1 4 zip 函数 1 5 enumerat
  • 在分布式环境下标准支付流程的梳理

    支付流程图的梳理 https www processon com diagraming 61a18a895653bb136f893ecc 提交订单 当用户点击立即购买或者提交订单的这个时候数据库就会记录一笔订单 此项业务主要是用到了rabb
  • Android 设置ListView不可滚动 及在ScrollView中不可滚动的设置

    转载请注明出处 http blog csdn net androiddevelop article details 38815493 希望得到的效果是ListView不能滚动 但是最大的问题在与ListView Item还必有点击事件 如果
  • 2023华为OD机试真题【区间交叠/贪心算法】【Python Java C++】

    题目描述 给定坐标轴上的一组线段 线段的起点和终点均为整数并且长度不小于1 请你从中找到最少数量的线段 这些线段可以覆盖住所有线段 输入描述 第一行输入为所有线段的数量 不超过10000 后面每行表示一条线段 格式为 x y x和y 分别表
  • vscode因网络下载失败的问题

    复制出失败的下载链接 https az764295 vo msecnd net stable d045a5eda657f4d7b676dedbfa7aab8207f8a075 VSCodeUserSetup x64 1 72 2 exe 将
  • 多任务视频推荐方案,百度工程师实战经验分享

    推荐系统的应用场景非常广泛 比如非常火爆的短视频推荐 电商平台商品推荐 搜索推荐等 但是你知道吗 短视频APP在向你展示一个你感兴趣的视频之前 通常既要预测你对这个视频是否感兴趣 又要预测你会看多久 点赞还是不点赞 会不会偷偷收藏起来下次接
  • 迁移学习matlab

    迁移学习是一种机器学习技术 它可以利用已有的模型和数据来加速新模型的训练 在Matlab中实现迁移学习 需要先选定一个预训练的模型 然后使用该模型的权重来初始化新模型 最后对新模型进行微调以适应特定的任务 Matlab中有一些已经预先训练好
  • 常用函数式接口

    常用函数式接口 JDK 8 中重要的函数接口 接口 参数 返回 中文 示例 Supplier None T 提供者 工厂方法创建对象 Consumer T void 消费者 输出一个值 Predicate T boolean 谓语 顾名思义
  • 【Linux】编译器gcc和g++与调试器gdb的使用

    文章目录 一 Linux编译器 gcc g 1 程序运行的四个阶段 1 1 预处理 1 2 编译 1 3 汇编 1 4 链接 2 链接方式与函数库 2 1 动态链接与静态链接 2 2 动态库与静态库 3 gcc g 的使用 二 Linux调
  • C++11容器中新增加的emplace相关函数的使用

    C 11中 针对顺序容器 如vector deque list 新标准引入了三个新成员 emplace front emplace和emplace back 这些操作构造而不是拷贝元素 这些操作分别对应push front insert和p
  • Spark一路火花带闪电——Spark底层原理介绍

    文章目录 Spark计算引擎原理 1 1 术语 1 1 1 Application Spark应用程序 1 1 2 Driver 驱动程序 1 1 3 Cluster Manager 资源管理器 1 1 4 Executor 执行器 1 1
  • python---闭包

    1 闭包理解 闭包定义 在函数嵌套的前提下 内部函数使用了外部函数的变量 并且外部函数返回了内部函数 我们把这个使用外部函数变量的内部函数称为闭包 2 必报的构成条件 在函数嵌套 函数里面在定义函数 的前提下 内部函数使用了外部函数的变量