赞
踩
闭包定义:在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包
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
- # 可以创建多个闭包实例,不同的闭包实例之间,不会相互影响
案例:根据配置信息使用闭包实现不同人的对话信息,例如对话:
张三:到北京了吗?
李四:已经到了,放心吧。
实现步骤说明
定义外部函数接受不同的配置信息参数,参数是人名
定义内部函数接受对话信息参数
在内部函数里面把配置信息和对话信息进行拼接输出
- def outer(name):
- # 定义内部函数,参数是 说话的信息
- print(f'{name}:到北京了吗?')
-
- def inner(name1):
- # 内部函数中,将name和info进行拼接输出
- print(f'{name1}:已经到了,放心吧。')
-
- # 外部函数返回内部函数的地址
- return inner
-
-
- # 创建闭包实例
- if __name__ == '__main__':
- func = outer('张三')
- func('李四')
注意点:由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。
函数内部想要修改全局变量,使用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()
- 装饰器的功能:就是给已有函数添加新的功能
- 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()
- 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()
- 需求:
- 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)
不管原函数有没有返回值,装饰器的内部函数都应该将fn函数的返回值进行返回
如果原函数有返回值,返回的就是原函数的返回值
如果没有返回的是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)))
- def decorate(fn):
- def inner(*args,**kwargs):
- ...
- result=fn(*args,**kwargs)
- return result
- return inner
- 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!'))
- # 装饰器 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'))
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'))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。