本文为霍格沃兹测试开发学社学员学习笔记分享
原文链接:https://ceshiren.com/t/topic/27720
def show():
print("Show Run ...")
show()
a = show
a()
闭包(Closure)是指在一个嵌套的函数内部访问其外部函数中定义的变量或函数的能力。换句话说,闭包是一个函数对象,它可以记住并访问它创建时的上下文环境中的变量。
def out_func():
out_n = 100
def inner_func():
print(out_n)
return inner_func
if __name__ == '__main__':
of1 = out_func()
of2 = out_func()
of1()
of2()
global 在函数内部声明变量为全局变量。 闭包中要修改变量也是一样,内函数是不能直接修改外函数中定义的变量的,如果需要修改,要在内函数中使用 nonlocal 关键字声明该变量为外函数的变量。A、 不使用 nonlocal 修饰
def out_func():
out_n = 100
def inner_func():
out_n = 200
print("inner:",out_n)
print("outer1:",out_n)
inner_func()
print("outer2:",out_n)
return inner_func
if __name__ == '__main__':
of1 = out_func()
of1()
# 结果:
# outer1: 100
# inner: 200
# outer2: 100
# inner: 200
B、 使用 nonlocal 修饰
def out_func():
out_n = 100
def inner_func():
nonlocal out_n
out_n = 200
print("inner:",out_n)
print("outer1:",out_n)
inner_func()
print("outer2:",out_n)
return inner_func
if __name__ == '__main__':
of1 = out_func()
of1()
# 结果:
# outer1: 100
# inner: 200
# outer2: 200
# inner: 200
@ 符号加上装饰器名称,用于修改其他函数的行为,并且在不修改原始函数定义和调用的情况下添加额外的功能。# 需求,在不改动原函数基础上给原函数增加统计运行时间功能
import time
def run_time(func):
def inner():
# 开始计时
start_time = time.time()
# 原函数执行
func()
# 结束计时
end_time = time.time()
print(f"程序运行时间为:{end_time - start_time}秒")
return inner
@run_time
# 原函数
def show():
for i in range(1,13):
print(f"第{i}次打印")
if __name__ == '__main__':
show()
装饰器提供了一种简洁而优雅的方式(语法糖)来扩展和修改函数或类的功能。其本质就是函数的使用。
语法糖: 在计算机科学中,语法糖(Syntactic sugar)是指一种语法上的扩展,它并不改变编程语言的功能,只是提供了更便捷、更易读的写法,使得代码更加简洁和可理解。
常见的语法糖:
@run_time
# 原函数
def show():
Python解释器解释过程:
show = run_time(show)
前面示例代码可修改为:
import time
def run_time(func):
def inner():
# 开始计时
start_time = time.time()
# 原函数执行
func()
# 结束计时
end_time = time.time()
print(f"程序运行时间为:{end_time - start_time}秒")
return inner
# 原函数
def show():
for i in range(1,20):
print(f"第{i}次打印")
if __name__ == '__main__':
show = run_time(show)# run_time返回inner
show()# 这里执行的就是inner()函数
# 做为装饰器名的外函数,使用参数接收被装饰函数的引用
def decorator(func):
# 内函数的可变参数用来接收被装饰函数使用的参数
def inner(*args, **kwargs):
# 装饰器新增功能代码
# 调用被装饰函数,并将接收的参数传递给被装饰函数,保存被装饰函数执行结果
result = func(*args, **kwargs)
# 返回被装饰函数执行结果
return result
# 返回内函数引用
return inner
# 接收装饰器参数的函数
# 参数一:以字符串形式接收被装饰函数的参数列表,需要与被装饰函数参数名保持一致,例:"a,b,c"
# 参数二:以[(),(),()] 形式传入驱动数据。
def decorator_args(vars, datas):
def decorator(func):
# 将字符串参数分割备用
v_keys = vars.split(",")
# 定义保存 [{},{},{}] 形式的数据
new_datas = []
# 遍历数据,取出一组元素数据
for item in datas:
# 定义一个新字典,用来保存 变量名与传入数据组成的字典
d_item = {}
# 使用 zip 函数,同时遍历两个元组,变量名做为key, 元素数据做为value
for k, v in zip(v_keys, item):
# 将 变量名和值对应保存到字典中
d_item[k] = v
# 将组合好的字典追加到新数据中备用
new_datas.append(d_item)
def inner(*args, **kwargs):
return func(*args, **kwargs)
# 遍历新数据,取出元素字典
for item in new_datas:
# 将字典中的数据解包传给内函数
inner(**item)
return inner
return decorator
# 数据驱动数据
data = [(1,2,3),(4,5,6),(7,8,9)]
# 装饰器传参
@decorator_args("a,b,c", data)
def show(a,b,c):
print(a,b,c)
装饰器传参的本质就是链式语法的多次函数调用;
@decorator_args("a,b,c", data) 解析:
decorator_args("a,b,c", data)部分decorator与@结合变成装饰器形式@decorator@decorator 装饰器正常装饰被装饰函数作业要求:
"""
作业要求
编写一个Python程序,实现一个计数器函数,该函数能够记录特定函数的调用次数。你需要使用闭包和装饰器来实现这个功能。
"""
#给原函数增加统计调用次数功能
def count(func):
n = 0
def inner(number_1,operate,number_2):
nonlocal n
func(number_1,operate,number_2)
n += 1
print(f"函数被调用了{n}次")
return inner
# 原函数:简单打印操作
def compute(number_1,operate,number_2):
match operate:
case "+":
print(number_1 + number_2)
case "-":
print(number_1 - number_2)
case "*":
print(number_1 * number_2)
case "/":
print(number_1 / number_2)
case _:
print("对不起,您要求的计算我不会!")
if __name__ == '__main__':
nwe_computer = count(compute)
nwe_computer(5,"+",1)
nwe_computer(5,"-",1)
nwe_computer(5,"*",1)
nwe_computer(5,"/",1)
nwe_computer(5,"//",1)
"""
作业要求
编写一个Python程序,实现一个计数器函数,该函数能够记录特定函数的调用次数。你需要使用闭包和装饰器来实现这个功能。
"""
#给原函数增加统计调用次数功能
def count(func):
n = 0
def inner(number_1,operate,number_2):
nonlocal n
func(number_1,operate,number_2)
n += 1
print(f"函数被调用了{n}次")
return inner
# 原函数:简单打印操作
@ count
def compute(number_1,operate,number_2):
match operate:
case "+":
print(number_1 + number_2)
case "-":
print(number_1 - number_2)
case "*":
print(number_1 * number_2)
case "/":
print(number_1 / number_2)
case _:
print("对不起,您要求的计算我不会!")
if __name__ == '__main__':
compute(5,"+",1)
compute(5,"-",1)
compute(5,"*",1)
compute(5,"/",1)
compute(5,"//",1)