# 第 2-6 课课堂练习:装饰器 # # 请先阅读讲义并运行完整示例,再按照题目顺序完成。 # 装饰器必须调用原函数并保留原函数的返回值。 # 不要删除题目、测试数据、预期结果和自查注释。 # 第一部分:理解函数可以赋值给变量 # 1. 定义 greet_agent(name) 函数。 # 2. 函数 return f"你好,{name}。",不要在函数内部 print()。 # 3. 把 greet_agent 函数本身赋值给变量 greeting_function,赋值时不要写括号。 # 4. 调用 greeting_function("代码助手"),保存并输出返回值。 # 5. 预期结果:“你好,代码助手。”。 # greeting_function = greet_agent # print(greeting_function("代码助手")) # 第二部分:定义 log_call(func) 装饰器 # 1. 在 log_call() 内定义 wrapper(*args, **kwargs)。 # 2. 在 wrapper 上方使用 @wraps(func)。 # 3. wrapper 先输出 f"调用函数:{func.__name__}"。 # 4. 使用 func(*args, **kwargs) 调用原函数,并把返回值保存为 result。 # 5. wrapper return result,不能丢失原函数返回值。 # 6. log_call() return wrapper,注意不要写成 wrapper()。 # 第三部分:使用 @log_call # 1. 定义 get_agent_name(agent) 函数。 # 2. 在函数上方写 @log_call。 # 3. 函数 return agent["name"]。 # 4. 调用 get_agent_name(enabled_agent),保存并输出结果。 # 5. 预期先输出“调用函数:get_agent_name”,再得到“代码助手”。 # 6. 检查 get_agent_name.__name__,预期仍是 "get_agent_name"。 # print(get_agent_name(enabled_agent)) # print(get_agent_name.__name__) # 第四部分:定义 require_enabled(func) 装饰器 # 1. 在 require_enabled() 内定义 wrapper(agent, *args, **kwargs)。 # 2. 在 wrapper 上方使用 @wraps(func)。 # 3. 如果 agent.get("enabled", False) 为 False: # 输出“Agent 已停用,不能执行任务。”并 return None。 # 4. 如果 Agent 已启用,调用 func(agent, *args, **kwargs) 并 return 原结果。 # 5. require_enabled() return wrapper。 # 第五部分:使用 @require_enabled # 1. 定义 run_task(agent, task_name) 函数。 # 2. 在函数上方写 @require_enabled。 # 3. 函数 return f"{agent['name']} 正在执行:{task_name}"。 # 4. 传入 enabled_agent 和 "检查代码",预期返回: # “代码助手 正在执行:检查代码”。 # 5. 传入 disabled_agent 和 "整理对话",预期输出停用提示并返回 None。 # print(run_task(enabled_agent ,"检查代码")) # print(run_task(disabled_agent ,"整理对话")) # 第六部分:定义 main() 函数 # 1. 完成第一部分的函数赋值实验,并输出问候结果。 # 2. 调用 get_agent_name(enabled_agent),保存并输出返回值。 # 3. 输出 get_agent_name.__name__,确认 @wraps 保留了原函数名。 # 4. 分别使用启用和停用 Agent 调用 run_task()。 # 5. 保存并输出两个调用结果,停用 Agent 的结果应为 None。 # 6. 添加程序入口判断,直接运行本文件时调用 main()。 # 最终验收测试: # 1. greeting_function 与 greet_agent 指向同一个函数; # 2. greeting_function("代码助手") 返回正确文字; # 3. get_agent_name() 调用前输出函数名称; # 4. get_agent_name(enabled_agent) 返回“代码助手”; # 5. get_agent_name.__name__ 仍是 "get_agent_name"; # 6. run_task(enabled_agent, "检查代码") 返回正确文字; # 7. run_task(disabled_agent, "整理对话") 返回 None; # 8. 停用 Agent 不会执行原 run_task() 的函数主体; # 9. 两个装饰器都能接收参数并保留原函数返回值。 # 完成后自查: # 1. 是否理解函数名不加括号表示函数本身; # 2. 是否理解函数名加括号表示立即调用函数; # 3. 装饰器是否接收原函数并返回 wrapper; # 4. wrapper 是否调用并返回原函数结果; # 5. 是否使用 *args 和 **kwargs 转发参数; # 6. 是否使用 @wraps(func) 保留原函数信息; # 7. 是否能解释 @log_call 与手动重新赋值的关系; # 8. 是否保留了完整题目和验收说明。