Python函数定义详细教程:参数类型详解,报错UnboundLocalError怎么解决。
一、血泪教训:我在函数定义中踩过的那些坑
1.1 变量作用域的幽灵现象
# 错误示例:试图修改全局变量
total = 0
def calculate_sum(a, b):
total += a + b # 引发UnboundLocalError
return total
print(calculate_sum(3, 5)) # 报错!
报错原因:函数内部修改全局变量需显式声明 global
1.2 可变默认参数的离奇行为
# 错误示例:使用可变对象作为默认参数
def append_item(item, items=[]):
items.append(item)
return items
print(append_item(1)) # [1]
print(append_item(2)) # [1, 2] 结果不符合预期!
原理:默认参数在函数定义时创建,多次调用共享同一对象
二、解决方案:企业级函数定义技巧
2.1 正确使用作用域
# 正确方案:明确作用域
total = 0
def calculate_sum(a, b):
global total # 显式声明全局变量
total += a + b
return total
print(calculate_sum(3, 5)) # 8
2.2 安全处理默认参数
# 正确方案:不可变默认值+条件判断
def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(append_item(1)) # [1]
print(append_item(2)) # [2]
2.3 类型提示增强可读性(Python 3.5+)
from typing import List, Union
def process_data(
data: List[Union[int, str]],
prefix: str = "DEFAULT_"
) -> dict:
"""处理数据并返回字典"""
return {prefix + str(i): v for i, v in enumerate(data)}
三、知识图谱:函数定义核心要点
3.1 函数定义标准结构
def 函数名(参数列表) -> 返回类型:
"""文档字符串(Docstring)"""
函数体
return 返回值
3.2 参数类型详解
参数类型 | 语法 | 示例 | 特点 |
---|---|---|---|
位置参数 | def func(a) | func(1) | 必须按顺序传参 |
默认参数 | def func(a=0) | func() | 调用时可省略 |
可变位置参数 | *args | func(1,2,3) | 接收元组 |
可变关键字参数 | **kwargs | func(a=1,b=2) | 接收字典 |
3.3 高级技巧
-
闭包函数:函数内定义函数,保留外部作用域变量
def outer():
cache = []
def inner(x):
cache.append(x)
return sum(cache)/len(cache)
return inner
avg = outer()
print(avg(10)) # 10.0
print(avg(20)) # 15.0
-
Lambda表达式:单行匿名函数
square = lambda x: x**2
sorted_list = sorted([(1, 'a'), (3, 'c')], key=lambda x: x[1])
四、总结
在Python函数定义的实际开发中,理解作用域规则是避免变量污染的关键,全局变量修改必须显式声明,嵌套函数使用nonlocal关键字可访问外层非全局变量。默认参数务必使用不可变对象,列表、字典等可变类型应通过None占位符进行初始化。类型提示(Type Hints)虽不强制但能显著提升代码可维护性,结合文档字符串(Docstring)形成良好的编码规范。参数设计应遵循“位置参数→默认参数→可变参数”的顺序,*args用于接收任意数量位置参数,**kwargs处理关键字参数。异常处理建议在函数内部完成,通过返回值或异常对象向上传递错误信息。装饰器(@decorator)可扩展函数功能,但要注意保持装饰器的纯粹性。掌握这些要点后,函数将成为构建复杂程序的可靠基石,合理划分函数职责能提升代码复用率,降低模块耦合度,使项目更易维护和扩展。
你们有什么踩坑记录,评论区探讨一下?