1.闭包
闭包(Closure)是指在一个函数内部定义的函数,并且这个内部函数可以访问其外部函数作用域中定义的变量。在 Python 中,闭包是一个强大且灵活的编程工具,可以实现许多有趣和实用的功能。
让我们通过一个简单的示例来说明闭包的基本概念:
def outer_function(x):
def inner_function(y): # 内部函数
return x + y
return inner_function # 外部函数返回内部函数的引用
closure = outer_function(10) # 创建闭包
result = closure(5) # 调用闭包
print(result) # 输出 15
在这个例子中:
outer_function
是外部函数,接受一个参数x
。inner_function
是内部函数,它接受参数y
,并返回x + y
的结果。outer_function(10)
调用返回了inner_function
的引用,并且在这个过程中x
被设置为 10。- 我们将
outer_function(10)
的返回结果赋给closure
,这个closure
就成为了一个闭包。 - 当我们调用
closure(5)
时,实际上是在调用inner_function
,这时闭包中的x
值为 10,所以结果为 10 + 5 = 15。
总结三点就是:闭包的形成一定是有外部函数嵌套内部函数、外部函数返回值为内部函数、内部函数可以访问外部函数的局部变量。
闭包在实际编程中有许多应用,例如:
- 工厂函数:通过闭包可以动态生成函数,根据不同的输入参数生成不同的逻辑。
- 装饰器:装饰器本质上就是闭包,它可以在不修改函数源代码的情况下,添加额外的功能。
- 回调函数:将函数作为参数传递给其他函数,形成闭包,可以在异步编程中非常有用。
在使用闭包时,需要注意以下几点:
- 变量绑定时间:闭包中的自由变量在定义时被绑定,而不是在调用时。
- 内存管理:闭包会保留外部函数的环境,可能会导致内存占用问题,尤其是在闭包的作用域很大或者存在循环引用时。
2.装饰器
Python装饰器是一种高级功能,它允许在不改变函数本身代码的情况下,动态地修改或者增强函数的行为。装饰器本质上是一个函数,它接受一个函数作为输入,并返回一个新的函数作为输出。在函数执行之前或之后,装饰器允许添加额外的功能。
让我们通过一个简单的示例来说明装饰器的基本用法:
def decorator_function(func): # 定义一个装饰器函数
def wrapper():
print("Wrapper executed this before {}".format(func.__name__))
return func() # 执行原始函数
return wrapper
def say_hello(): # 定义一个普通函数
print("Hello!")
say_hello = decorator_function(say_hello) # 使用装饰器来增强函数的功能
say_hello()# 调用经过装饰的函数
在这个例子中:
decorator_function
是一个装饰器函数,它接受一个函数func
作为参数。wrapper
函数是装饰器内部定义的函数,它在调用被装饰的函数之前添加了额外的功能。- 最后,我们通过
say_hello = decorator_function(say_hello)
将say_hello
函数应用了decorator_function
装饰器。
可以看出,其实装饰器是合理运用了闭包的特性,在内部函数调用了外部函数的形参函数。在内部函数对调用的函数进行功能装饰,实现不改变原有函数功能的基础上增添了新的功能实现。并且,不单单是某个函数可以被内部函数调用进行装饰,还可以有很多个一起。
在上述例子中,还可以换一种专属于装饰器的写法。
def decorator_function(func): # 定义一个装饰器函数
def wrapper():
print("Wrapper executed this before {}".format(func.__name__))
return func() # 执行原始函数
return wrapper
@decorator_function # 在函数前加一顶“帽子”,用@ 将 target_function 函数传递给 decorator 装饰器,并将返回的函数重新赋值给 target_function。
def say_hello(): # 定义一个普通函数
print("Hello!")
say_hello() # 调用经过装饰的函数
可以看出,装饰器通过 @ 符号应用在函数定义之前,会将 target_function 函数传递给 decorator 装饰器,并将返回的函数重新赋值给 target_function。从而,每次调用 target_function 时,实际上是调用了经过装饰器处理后的函数。
装饰器的应用场景:
- 日志记录: 装饰器可用于记录函数的调用信息、参数和返回值。
- 性能分析: 可以使用装饰器来测量函数的执行时间。
- 权限控制: 装饰器可用于限制对某些函数的访问权限。
- 缓存: 装饰器可用于实现函数结果的缓存,以提高性能。
通过装饰器,开发者可以在保持代码整洁的同时,灵活且高效地扩展程序的功能。
3.装饰器案例
在几个案例中去了解一下装饰器的一些使用情况和方式。
user = None
def index():
print("欢迎来到小宇家杂货铺")
def login_required(f):
def check():
global user
if user:
f()
else:
while True:
username = input("请输入用户名")
password = input("请输入密码")
if username == "cxy" and password == "123456":
f()
user = {"username": username, "password": password}
break
else:
print("用户名和密码错误")
return check
@login_required
def go_center():
print("进入个人中心成功")
@login_required
def go_cart():
print("进入购物车成功")
@login_required
def go_search():
print("进入搜索页成功")
index()
go_center()
go_cart()
上述案例是模仿在某购物平台进行的用户登录,无论在哪里进行用户登录,之后都可以通过登录数据跳过登录选项,也是运用装饰器的功能实现装饰三个需要相同功能的地方。
不仅如此,装饰器函数也可以接受参数。
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
以上代码中 repeat 函数是一个带参数的装饰器,它接受一个整数参数 n,然后返回一个装饰器函数。该装饰器函数内部定义了 wrapper 函数,在调用原始函数之前重复执行 n 次。因此,greet 函数在被 @repeat(3) 装饰后,会打印三次问候语。
Python 还允许将多个装饰器堆叠在一起,按照从上到下的顺序应用:
def decorator1(func):
def wrapper():
print("Decorator 1 executed")
return func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2 executed")
return func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()
在这个例子中,先应用 @decorator2
,再应用 @decorator1
,最终调用 say_hello()
时会按照 Decorator 1 executed
和 Decorator 2 executed
的顺序输出。
最后运用装饰器来实现对比两个函数的执行效率。
import random
import time
datas = [random.randint(0, 10000) for i in range(10000)]
# 浅拷贝一个数据,得到两个一样的值
data = datas.copy()
# 定义一个时间耗费函数装饰器
def time_coast(f):
def calc():
start = time.time()
f()
print(time.time() - start)
return calc
# 对函数一进行装饰
@time_coast
def fun1():
# 对数据进行方法一排序
datas.sort()
print(datas)
# 对函数二进行装饰
@time_coast
def fun2():
# 对浅拷贝出来的数据进行方式二排序
new_data = sorted(data)
print(new_data)
# 执行装饰后的函数,比较两个函数花费时间那个少
fun1()
fun2()
可以看出,装饰器的调用,实现了查看两函数的执行耗费时间,但是没有改变原有函数的功能。装饰器的存在,让我们在编程时,可以给函数添加更多更丰富的功能的同时,又不会让我们的代码看起来繁琐杂乱。
标签:闭包,function,函数,Python,print,装饰,def From: https://blog.csdn.net/2402_86120726/article/details/140617636