闭包基础(必做)
定义外部函数 func_out(num1),内部函数 func_inner(num2)。
内部函数使用外部变量完成求和并打印。
外部函数返回内部函数,创建闭包并调用。
解释每一行如何对应"有嵌套/有引用/有返回"三条件。
查看参考答案 ▼
def func_out(num1):
def func_inner(num2):
# 内部函数引用了外层变量 num1 ——"有引用"</span>
print("结果:", num1 + num2)
# 外部函数返回内部函数名 ——"有返回"</span>
return func_inner
# 创建闭包:num1=10 被内部函数"记住"</span>
f = func_out(10)
# 调用闭包,num2=5
f(5) # 输出:结果: 15
✓ 正确
参考答案:def func_out(num1):
def func_inner(num2):
# 内部函数引用了外层变量 num1 ——"有引用"</span>
print("结果:", num1 + num2)
# 外部函数返回内部函数名 ——"有返回"</span>
return func_inner
# 创建闭包:num1=10 被内部函数"记住"</span>
f = func_out(10)
# 调用闭包,num2=5
f(5) # 输出:结果: 15
nonlocal 闭包计数器(必做)
编写 counter(),外层定义 count = 0。
内层函数每调用一次 count + 1 并返回新值。
必须使用 nonlocal,并连续调用至少 3 次验证状态被保存。
查看参考答案 ▼
def counter():
count = 0
def add_one():
# nonlocal 声明要修改外层变量
nonlocal count
count += 1
return count
return add_one
c = counter()
print(c(), c(), c()) # 输出: 1 2 3
✓ 正确
参考答案:def counter():
count = 0
def add_one():
# nonlocal 声明要修改外层变量
nonlocal count
count += 1
return count
return add_one
c = counter()
print(c(), c(), c()) # 输出: 1 2 3
装饰器原始写法与语法糖(必做)
定义登录校验装饰器 check。
用原始方式 comment = check(comment) 装饰一次。
再用 @check 语法糖装饰另一个函数。
对比两种写法并在注释中写出"等价关系"。
查看参考答案 ▼
def check(fn):
def inner():
print("请先登录")
fn()
return inner
def comment():
print("发表评论")
# 原始方式:手动调用装饰器
comment = check(comment)
comment()
# 语法糖方式:@check 等价于 like = check(like)</span>
@check
def like():
print("点赞")
like()
✓ 正确
参考答案:def check(fn):
def inner():
print("请先登录")
fn()
return inner
def comment():
print("发表评论")
# 原始方式:手动调用装饰器
comment = check(comment)
comment()
# 语法糖方式:@check 等价于 like = check(like)</span>
@check
def like():
print("点赞")
like()
通用装饰器(重点必做)
编写一个通用装饰器,内部函数使用 *args, **kwargs。
要求可装饰四类函数:1) 无参无返回 2) 有参无返回 3) 无参有返回 4) 有参有返回(含关键字参数)。
演示调用结果,证明"参数和返回值都不丢失"。
查看参考答案 ▼
def universal_decorator(func):
def inner(*args, **kwargs):
print(">>> 增强逻辑开始")
# 透传所有参数并接收返回值
result = func(*args, **kwargs)
print(">>> 增强逻辑结束")
# 必须 return 保证返回值不丢失
return result
return inner
# 测试四类函数
@universal_decorator
def test1(): print("无参无返回")
@universal_decorator
def test2(name): print(f"有参: {name}")
@universal_decorator
def test3(): return "有返回"
@universal_decorator
def test4(a, b, c=0): return a + b + c
test1()
test2("张三")
print(test3()) # 输出: 有返回
print(test4(1, 2, c=3)) # 输出: 6
✓ 正确
参考答案:def universal_decorator(func):
def inner(*args, **kwargs):
print(">>> 增强逻辑开始")
# 透传所有参数并接收返回值
result = func(*args, **kwargs)
print(">>> 增强逻辑结束")
# 必须 return 保证返回值不丢失
return result
return inner
# 测试四类函数
@universal_decorator
def test1(): print("无参无返回")
@universal_decorator
def test2(name): print(f"有参: {name}")
@universal_decorator
def test3(): return "有返回"
@universal_decorator
def test4(a, b, c=0): return a + b + c
test1()
test2("张三")
print(test3()) # 输出: 有返回
print(test4(1, 2, c=3)) # 输出: 6
多装饰器执行顺序(重点必做)
定义两个装饰器 deco1、deco2,分别打印"前/后"日志。
同时装饰一个函数,观察执行顺序。
用注释写清楚:谁先装饰、谁先执行。
查看参考答案 ▼
def deco1(fn):
def inner():
print("deco1 前")
fn()
print("deco1 后")
return inner
def deco2(fn):
def inner():
print("deco2 前")
fn()
print("deco2 后")
return inner
# deco2 离函数最近,先装饰(先包裹)
# 执行顺序:deco1前 → deco2前 → 原函数 → deco2后 → deco1后
@deco1
@deco2
def work():
print("原函数执行")
work()
# 输出:
# deco1 前
# deco2 前
# 原函数执行
# deco2 后
# deco1 后
✓ 正确
参考答案:def deco1(fn):
def inner():
print("deco1 前")
fn()
print("deco1 后")
return inner
def deco2(fn):
def inner():
print("deco2 前")
fn()
print("deco2 后")
return inner
# deco2 离函数最近,先装饰(先包裹)
# 执行顺序:deco1前 → deco2前 → 原函数 → deco2后 → deco1后
@deco1
@deco2
def work():
print("原函数执行")
work()
# 输出:
# deco1 前
# deco2 前
# 原函数执行
# deco2 后
# deco1 后
带参数装饰器(重点必做)
编写 logging(flag):当 flag 为 '+' 提示加法日志,'-' 提示减法日志。
用 @logging('+') 装饰 add(a,b)。
用 @logging('-') 装饰 sub(a,b)。
输出运算结果并验证装饰器参数生效。
查看参考答案 ▼
def logging(flag):
"""最外层接收装饰器参数"""
def decorator(fn):
"""中间层接收被装饰函数"""
def inner(a, b):
"""最内层做实际包装"""
if flag == "+":
print("正在进行加法计算")
elif flag == "-":
print("正在进行减法计算")
# 调用原函数并返回结果
return fn(a, b)
return inner
return decorator
@logging("+")
def add(a, b):
return a + b
@logging("-")
def sub(a, b):
return a - b
print(add(1, 3)) # 输出: 正在进行加法计算 / 4
print(sub(5, 2)) # 输出: 正在进行减法计算 / 3
✓ 正确
参考答案:def logging(flag):
"""最外层接收装饰器参数"""
def decorator(fn):
"""中间层接收被装饰函数"""
def inner(a, b):
"""最内层做实际包装"""
if flag == "+":
print("正在进行加法计算")
elif flag == "-":
print("正在进行减法计算")
# 调用原函数并返回结果
return fn(a, b)
return inner
return decorator
@logging("+")
def add(a, b):
return a + b
@logging("-")
def sub(a, b):
return a - b
print(add(1, 3)) # 输出: 正在进行加法计算 / 4
print(sub(5, 2)) # 输出: 正在进行减法计算 / 3
挑战题:函数耗时统计装饰器
实现一个"函数耗时统计装饰器",输出函数名和执行时长。
提示:使用 time.time() 记录开始和结束时间,计算差值。
查看参考答案 ▼
import time
def timer(func):
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"函数 {func.__name__} 执行耗时: {end - start:.4f} 秒")
return result
return inner
@timer
def slow_func():
total = 0
for i in range(1000000):
total += i
return total
print(slow_func())
✓ 正确
参考答案:import time
def timer(func):
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"函数 {func.__name__} 执行耗时: {end - start:.4f} 秒")
return result
return inner
@timer
def slow_func():
total = 0
for i in range(1000000):
total += i
return total
print(slow_func())
挑战题:权限装饰器
实现一个"权限装饰器":未登录拒绝执行,登录后放行。
提示:用一个全局变量模拟登录状态,装饰器内部判断状态后决定是否调用原函数。
查看参考答案 ▼
# 模拟登录状态
is_login = False
def login_required(func):
def inner(*args, **kwargs):
if is_login:
return func(*args, **kwargs)
else:
print("请先登录后再操作!")
return inner
@login_required
def view_secret():
print("这是机密内容...")
# 未登录调用
view_secret() # 输出: 请先登录后再操作!
# 登录后调用
is_login = True
view_secret() # 输出: 这是机密内容...
✓ 正确
参考答案:# 模拟登录状态
is_login = False
def login_required(func):
def inner(*args, **kwargs):
if is_login:
return func(*args, **kwargs)
else:
print("请先登录后再操作!")
return inner
@login_required
def view_secret():
print("这是机密内容...")
# 未登录调用
view_secret() # 输出: 请先登录后再操作!
# 登录后调用
is_login = True
view_secret() # 输出: 这是机密内容...