1. Python函数与装饰器入门指南
刚接触Python编程时,函数就像是我们日常使用的工具包。想象一下,你每次做饭都需要切菜——与其每次都重新学习如何握刀,不如把"切菜"这个动作打包成一个固定流程,这就是函数的基本思想。而装饰器则像是给这个工具包添加新功能的扩展配件,让你不用改变工具本身就能升级它的能力。
我在实际教学中发现,很多初学者在函数部分进展顺利,但一到装饰器就卡壳。这主要是因为大多数教程把装饰器讲得过于抽象。今天我就用最接地气的方式,带你从基础函数一直玩转装饰器,分享我在实际项目中使用它们的心得体会。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 函数基础:代码复用的艺术
2.1 函数定义与调用
Python中定义函数就像写一个菜谱:
python复制def 菜谱名称(食材参数):
"""这里是说明文档"""
处理食材的步骤
return 做好的菜
举个例子,我们写个计算圆面积的函数:
python复制def calculate_circle_area(radius):
"""计算圆的面积"""
area = 3.14159 * radius ** 2
return area
调用时直接使用函数名加括号:
python复制print(calculate_circle_area(5)) # 输出78.53975
经验之谈:函数名应该使用小写字母和下划线组合,动词开头更能体现函数的功能性。比如
get_user_info()比user_info()更符合规范。
2.2 参数传递的四种方式
- 位置参数:最常见的传参方式,按顺序匹配
python复制def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("小明", "你好") # 位置对应
- 关键字参数:明确指定参数名,顺序不重要
python复制greet(greeting="嗨", name="小红") # 关键字指定
- 默认参数:给参数预设默认值
python复制def greet(name, greeting="你好"):
print(f"{greeting}, {name}!")
greet("小刚") # 使用默认问候语
- 可变参数:处理不确定数量的输入
python复制def sum_numbers(*args):
return sum(args)
print(sum_numbers(1, 2, 3, 4)) # 输出10
踩坑提醒:默认参数要避免使用可变对象(如列表、字典),因为它们会在函数调用间保持状态。应该用None代替:
python复制# 错误示范
def add_item(item, items=[]):
items.append(item)
return items
# 正确做法
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
3. 函数进阶:理解作用域与闭包
3.1 变量作用域解析
Python有四种作用域:
- 局部作用域(Local)
- 嵌套作用域(Enclosing)
- 全局作用域(Global)
- 内置作用域(Built-in)
这就是著名的LEGB规则。看个例子:
python复制x = "全局变量"
def outer():
y = "嵌套变量"
def inner():
z = "局部变量"
print(z) # 访问局部
print(y) # 访问嵌套
print(x) # 访问全局
print(len) # 访问内置(len函数)
inner()
outer()
3.2 闭包:函数记住出生地
闭包是指内部函数记住了外部函数作用域中的变量,即使外部函数已经执行完毕:
python复制def make_multiplier(factor):
def multiplier(number):
return number * factor
return multiplier
double = make_multiplier(2)
print(double(5)) # 输出10
这里multiplier函数记住了factor=2,这就是闭包的魔力。我在实际项目中常用闭包来创建特定配置的函数工厂。
调试技巧:使用
__closure__属性查看闭包捕获的变量:
python复制print(double.__closure__[0].cell_contents) # 输出2
4. 装饰器:不修改代码增强函数
4.1 装饰器基础概念
装饰器本质上是一个接受函数作为参数并返回函数的高阶函数。它就像给函数穿衣服:
python复制def 衣服(原始函数):
def 穿好衣服的函数(*args, **kwargs):
# 穿衣服的代码
结果 = 原始函数(*args, **kwargs)
# 整理衣服的代码
return 结果
return 穿好衣服的函数
举个计时装饰器的例子:
python复制import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__}执行耗时: {end-start:.4f}秒")
return result
return wrapper
@timer
def long_running_func():
time.sleep(2)
long_running_func() # 输出"long_running_func执行耗时: 2.0002秒"
4.2 装饰器的多种写法
- 基础装饰器:如上例所示
- 带参数的装饰器:需要三层嵌套
python复制def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # 打印三次问候
- 类装饰器:通过实现
__call__方法
python复制class CountCalls:
def __init__(self, func):
self.func = func
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
print(f"这是第{self.calls}次调用{self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello() # 输出调用次数
say_hello() # 次数递增
4.3 保留函数元信息
装饰器会覆盖原函数的__name__等元信息,使用functools.wraps可以保留:
python复制from functools import wraps
def logit(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logit
def add(a, b)
