闭包
闭包的作用:闭包可以保存外部函数内的变量,不会随着外部函数调用完而销毁。 注意点:由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。 闭包的形成条件 1. 函数嵌套 2. 内部函数使用了外部函数的变量或者参数 3. 外部函数返回内部函数, 这个使用了外部函数变量的内部函数称为闭包
# 1. 函数嵌套
def func_out():
# 外部函数
num1 = 10
def func_inner(num2):
# 内部函数
# 2. 内部函数必须使用了外部函数的变量
result = num1 + num2
print("结果:", result)
# 3. 外部函数要返回内部函数,这个使用了外部函数变量的内部函数称为闭包
return func_inner
# 获取闭包对象
# 这个new_func就是闭包
# 这里的new_func = func_inner
new_func = func_out()
# 执行闭包
new_func(1)
new_func(10)
案例:闭包的使用
# 外部函数接收姓名参数
def config_name(name):
# 内部函数保存外部函数的参数,并且完成数据显示的组成
def inner(msg):
print(name + ":" + msg)
print(id(inner))
# 外部函数要返回内部函数
return inner
# 创建tom闭包实例(对象)
tom = config_name("tom")
# 创建jerry闭包实例
jerry = config_name("jerry")
# 如果执行tom闭包,因为已经保存了name参数,那么以后在输入的时候都是,tom说:xxx
tom("哥们,过来一下,我们一起玩耍!")
jerry("打死都不去!")
tom("我不吃你")
jerry("谁相信你")
修改闭包内使用的外部变量
# 1. 函数嵌套
def func_out():
# 外部函数的变量
num1 = 10
def func_inner():
# 在闭包内修改外部函数的变量
# num1 = 20 # 本意是修改外部函数变量, 其实是在闭包内定义了一个局部变量
# 在闭包内修改外部函数的变量需要使用nonlocal关键字
nonlocal num1
num1 = 20
# 2.内部要使用外部函数的变量
result = num1 + 10
print(result)
print("修改前的外部变量:", num1)
func_inner()
print("修改后的外部变量:", num1)
# 3. 返回内部函数
return func_inner
# 创建闭包对象
new_func = func_out()
new_func()
装饰器
装饰器定义: 对已有函数进行额外的功能扩展, 装饰器本质上一个闭包函数,也就是说他也是一个函数嵌套 装饰器的特点: 1. 不修改已有函数的源代码 2. 不修改已有函数的调用方式 3. 给以后函数添加额外的功能
# 定义装饰器
def decorator(func): # 如果闭包函数的参数有且只有一个并且是函数类型,那么这个闭包函数称为装饰器
print("装饰器执行了")
def inner():
# 在内部函数里面对已有函数进行装饰
print("已添加登陆验证")
func()
return inner
# 装饰器的语法糖写法: @装饰器名称,装饰器的语法糖就是在装饰以后函数的时候写法更加简单
@decorator # comment = decorator(comment) 装饰器语法糖对该代码进行了封装 comment=inner
def comment():
print("发表评论")
# 已添加登陆验证
# 发表评论
# # 调用装饰器对已有函数进行装饰 , comment=inner
# comment = decorator(comment)
# 调用方式不变
comment()
# 装饰器的执行时机: 当当前模块加载完成以后,装饰器会立即执行,对已有函数进行装饰
装饰器的执行时机: 当当前模块加载完成以后,装饰器会立即执行,对已有函数进行装饰
import mydecorator # 导入有装饰器模块
mydecorator.comment()
装饰器的使用场景
函数执行时间的统计
输出日志信息
# 定义装饰器
def decorator(func):
def inner():
# 内部函数对已有函数进行装饰
# 获取时间距离1970-1-1:0:0:1的时间差
begin = time.time()
func()
end = time.time()
result = end - begin
print("函数执行完成耗时:", result)
return inner
@decorator # work = decorator(work), work = inner
def work():
for i in range(10000):
print(i)
work()
通用的装饰器: 可以装饰任意类型的函数
--------装饰带有参数的函数
# 定义装饰器
def decorator(func):
# 使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致
def inner(a, b):
# 在内部函数对已有函数进行装饰
print("正在努力执行加法计算")
func(a, b)
return inner
# 用装饰器语法糖方式装饰带有参数的函数
@decorator # add_num= decorator(add_num), add_num=inner
def add_num(num1, num2):
result = num1 + num2
print("结果为:", result)
add_num(1, 2)
------装饰带有参数和返回值的函数
def decorator(func):
# 使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致
def inner(a, b):
# 在内部函数对已有函数进行装饰
print("正在努力执行加法计算")
num = func(a, b)
return num
return inner
# 用装饰器语法糖方式装饰带有参数的函数
@decorator # add_num= decorator(add_num), add_num=inner
def add_num(num1, num2):
result = num1 + num2
return result
result = add_num(1, 2)
print("结果为:", result)
----装饰带有不定长参数和返回值的函数
# 该装饰器还可以成为是通用的装饰器
def decorator(func):
# 使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致
def inner(*args, **kwargs):
# 在内部函数对已有函数进行装饰
print("正在努力执行加法计算")
# *args: 把元组里面的每一个元素,按照位置参数的方式进行传参
# **kwargs: 把字典里面的每一个键值对,按照关键字的方式进行传参
# 这里对元组和字典进行拆包,仅限于结合不定长参数的函数使用
num = func(*args, **kwargs)
return num
return inner
@decorator # show= decorator(show) show = inner
def show():
return "哈哈"
result = show()
print(result)
---- 用装饰器语法糖方式装饰带有参数的函数
def decorator(func):
# 使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致
def inner(*args, **kwargs):
# 在内部函数对已有函数进行装饰
print("正在努力执行加法计算")
# *args: 把元组里面的每一个元素,按照位置参数的方式进行传参
# **kwargs: 把字典里面的每一个键值对,按照关键字的方式进行传参
# 这里对元组和字典进行拆包,仅限于结合不定长参数的函数使用
num = func(*args, **kwargs)
return num
@decorator # add_num= decorator(add_num), add_num=inner
def add_num(*args, **kwargs):
result = 0
# args: 元组类型
# kwargs: 字典类型
for value in args:
result += value
for value in kwargs.values():
result += value
return result
result = add_num(1, 2)
print("结果为:", result)
# 错误写法
# if __name__ == '__main__':
# my = {"a":1}
# print(**my)
多个装饰器的使用 多个装饰器的装饰过程: 由内到外的一个装饰过程,先执行内部的装饰器,在执行外部的装饰器
def make_div(func):
print("make_div装饰器执行了")
def inner():
# 在内部函数对已有函数进行装饰
result = "<div>" + func() + "</div>"
return result
return inner
# 定义装饰器
def make_p(func):
print("make_p装饰器执行了")
def inner():
# 在内部函数对已有函数进行装饰
result = "<p>" + func() + "</p>"
return result
return inner
# 多个装饰器的装饰过程: 由内到外的一个装饰过程,先执行内部的装饰器,在执行外部的装饰器
# 原理剖析: content = make_div(make_p(content))
# 分步拆解: content = make_p(content),内部装饰器装完成content=make_p.inner
# content = make_div(make_p.inner)
@make_div
@make_p
def content():
return "人生苦短,我用python!"
# <p>人生苦短,我用python!</p>
result = content()
print(result)
带有参数的装饰器 带有参数的装饰器,其实就是定义了一个函数,让函数接收参数,在函数内部返回的是一个装饰器
def return_decorator(flag):
# 装饰器, 装饰器只能接收一个参数并且是函数类型
def decorator(func):
def inner(a, b):
if flag == "+":
print("正在努力执行加法计算")
elif flag == "-":
print("正在努力执行减法计算")
func(a, b)
return inner
# 当调用函数的时候可以返回一个装饰器decorator
return decorator
# 加法计算
@return_decorator("+") # decorator = return_decorator("+"), @decorator => add_num=decorator(add_num)
def add_num(a, b):
result = a + b
print(result)
add_num(1, 2)
# # 减法计算
@return_decorator("-")
def sub_num(a, b):
result = a - b
print(result)
add_num(1, 2)
sub_num(1, 4)
# 带有参数的装饰器,其实就是定义了一个函数,让函数接收参数,在函数内部返回的是一个装饰器
类装饰器: 使用类装饰已有函数
# # 类装饰器: 使用类装饰已有函数
class MyDecorator(object):
def __init__(self, func):
self.__func = func
# 实现__call__这个方法,让对象变成可调用的对象,可调用的对象能够像函数使用
def __call__(self, *args, **kwargs):
# 对已有函数进行封装
print("课已讲完")
self.__func()
@MyDecorator # @MyDecorator => show = MyDecorator(show)
def show():
print("快要下学啦")
# 执行show # 执行MyDecorator类创建实例对象 -> show() => 对象()
show()
# class AAA(object):
# pass
#
# a = AAA()
# a()
# 扩展: 函数之所有能够调用是因为函数内部使用__call__
def mytest():
print("哈哈")
print(dir(mytest))