1、函数作为参数(回调函数)
函数也是一种数据:function类型的数据。
回调函数:
作为参数的函数,将回调函数作为其他函数参数。
定义一个函数,该函数接收一个函数作为参数,并在函数执行完毕后执行回调函数。
def f1(a,b): # 定义一个函数,作为回调函数
return a+b
def f2(a,b): # 定义一个函数,作为被调用函数
return a-b
def fn(x,y,fun): #fun必须是函数
print(fun(x,y))
# 调用fn函数,并传入f2函数和f1函数作为参数
fn(10,5,f1)
fn(10,5,f2)
f1 和 f2 被定义为回调函数,而 fn 是一个被调用函数。回调函数是指作为参数传递给另一个函数的函数,这个被调用的函数在适当的时候会调用这个回调函数。
具体来说:
f1(a, b)是一个回调函数,它接收两个参数a和b,并返回它们的和。f2(a, b)也是一个回调函数,它接收两个参数a和b,并返回它们的差。fn(x, y, fun)是一个被调用函数,它接收两个数值参数x和y,以及一个函数参数fun。在函数体内,fun(x, y)被调用,即回调函数在fn函数内部被调用。
在代码的最后两行中,fn(10,5,f1) 和 fn(10,5,f2) 分别将 f1 和 f2 作为回调函数传递给 fn 函数,并执行相应的操作:
fn(10,5,f1)会调用f1(10,5),输出结果为15。fn(10,5,f2)会调用f2(10,5),输出结果为5。
2、函数作为返回值(闭包)
闭包是指引用了此函数外部嵌套函数的变量的函数,并把该函数作为返回值,是一种思想。
函数内部有函数,内部的那个函数就是闭包。
使用闭包(函数)来把环境的值单独保存起来,让变量不要相互污染。
闭包必须满足以下三个条件:
-
必须有一个内嵌函数
-
内嵌函数必须引用外部函数中变量
-
外部函数返回值必须是内嵌函数
# 闭包的定义和使用
def outer(x):
def inner(y):
return x + y
return inner # 这里返回的是 inner 函数的引用,而不是 inner 函数的执行结果
# 调用
f = outer(10) # 这里返回的是 inner 函数的引用
print(f(5)) # 15
3、装饰器
装饰器是Python对闭包思想的具体语法实现,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能。
-
日志记录:可以使用装饰器来记录函数的输入、输出或执行时间。
-
认证和授权:装饰器可以用于检查用户是否有权限执行特定操作。
-
缓存:装饰器可以缓存函数的结果,从而提高执行效率。
-
参数验证:可以使用装饰器来验证函数的输入参数是否符合预期。
-
代码注入:装饰器可以在函数的执行前后注入额外的代码。
3.1基本装饰器
通过一下过程来理解装饰器
计算x内的平方和
#计算x内的平方和
def f(x):
s = 0
for i in range(x):
s += i**2
return s
print(f(10000000))
我想知道f()函数的运行时间。
#我想知道f()函数的运行时间,可以用time模块来测试。
import time
def f(x):
t = time.time()
s = 0
for i in range(x):
s += i**2
t1 = time.time()
print("f()函数运行时间:", t1-t)
return s
print(f(50000000))
如果我还有很多函数(几千几万个函数)需要测试运行时间,每个函数都要写一遍time.time()和print()语句,那岂不是很麻烦?
将每个函数相同的功能都放在一个函数(装饰器函数)里,要使用时就对目标函数装饰。
所以,我们可以用装饰器来自动测试运行时间。
import time
# 装饰器函数
def fun(func):
def fn(*a,**b): # *a、**b 不管有多少参数,都接受
t = time.time()
result = func(*a,**b) # 调用原函数
t1 = time.time()
print(f"{func.__name__}函数运行时间:{t1-t}")
return result # 返回原函数的返回值
return fn # 返回装饰器函数
#目标函数
def f(x):
s = 0
for i in range(x):
s += i**2
return s
# 现在只要把f()函数转入fun(),f()函数没有计算时间的语句也会自动计算运行时间。
f = fun(f)
print(f(50000000))
可以不用写f = fun(f)也能实现同样的效果。python提供了一个语法糖@fun,可以直接把fun()函数应用到f()函数上。
#在目标函数前面加上@+装饰器函数名,如:@fun,相当于f = fun(f)。
import time
# 装饰器函数
def fun(func):
def fn(*a,**b): # *a、**b 不管有多少参数,都接受
t = time.time()
result = func(*a,**b) # 调用目标函数
t1 = time.time()
print(f"{func.__name__}函数运行时间:{t1-t}")
return result # 返回原函数的返回值
return fn # 返回装饰器函数
#目标函数f()
@fun
def f(x):
s = 0
for i in range(x):
s += i**2
return s
print(f(50000000)) #这里的f()函数已经不是原来的目标函数f()了,而是经过fun()函数装饰过的函数,只是函数名没有变化。
#现在,我们可以用@fun装饰器来自动测试需要测试的函数的运行时间,而不需要在每个函数中都写一遍time.time()和print()语句。
#不管有多少函数,都可以用同样的方式来测试运行时间。
3.2 带参装饰器
def repeat(num):
print('...函数名...()...函数执行...')
def decorator(func):
print('...装饰器...()...装饰器执行...')
def wrapper(*args, **kwargs):
for _ in range(num):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) # 应用装饰器,重复执行下面的函数3次
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # 调用被装饰的函数
-
repeat 是一个接受参数的装饰器工厂函数,它返回一个装饰器。
-
decorator 是真正的装饰器,它接受一个函数 func 作为参数。
-
wrapper 函数重复执行被装饰的函数
num次。
3.3 装饰器链
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def exclamation(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result + "!"
return wrapper
@exclamation
@uppercase
def say_hello(name):
return f"Hello, {name}"
greeting = say_hello("Bob")
print(greeting) # 输出 "HELLO, BOB!"
-
uppercase 和 exclamation 是两个装饰器,分别将文本转换为大写和添加感叹号。
-
使用
@exclamation和@uppercase创建装饰器链,它们按照声明的顺序依次应用。
336

被折叠的 条评论
为什么被折叠?



