
Python自定义函数完全指南:从零基础到闭包实战,让你的代码更简洁高效!
在日常编程中,你是否遇到过重复复制粘贴代码的烦恼?自定义函数就是解决这一问题的"万能钥匙",本文将带你从基础到进阶全面掌握Python函数的核心用法。
1. 为什么需要自定义函数?——从重复代码说起
先来看一个典型的重复代码场景——没有使用函数的成绩统计程序:
# 无函数版:统计3个学生成绩,代码重复严重
# 第1个学生
try:
score1 = float(input("请输入第1个学生成绩(0-100):"))
if score1 <0 or score1>100:
print("成绩超出范围")
except ValueError:
print("输入错误,请输数字")
# 第2个学生(复制粘贴第1个的代码,改序号)
try:
score2 = float(input("请输入第2个学生成绩(0-100):"))
if score2 <0 or score2>100:
print("成绩超出范围")
except ValueError:
print("输入错误,请输数字")
# 第3个学生(再复制一遍...)
try:
score3 = float(input("请输入第3个学生成绩(0-100):"))
if score3 <0 or score3>100:
print("成绩超出范围")
except ValueError:
print("输入错误,请输数字")
问题分析:
- 重复代码多,修改麻烦
- 容易出错(比如漏改序号)
- 扩展困难(统计10个学生要复制10遍)
解决方案:使用自定义函数将重复逻辑打包!
2. 函数基础:3步写出你的第一个函数
2.1 核心语法结构
def 函数名(参数1, 参数2, ...):
"""函数文档字符串"""
函数体代码
return 返回值 # 可选
2.2 实战:将重复代码改造成函数
def get_valid_score(student_num):
"""获取有效的学生成绩"""
while True:
try:
score = float(input(f"请输入第{student_num}个学生成绩(0-100):"))
if 0 <= score <= 100:
return score # 返回有效成绩
print("错误:成绩需在0-100之间")
except ValueError:
print("错误:请输入数字(如88.5)")
# 调用函数
score1 = get_valid_score(1)
score2 = get_valid_score(2)
score3 = get_valid_score(3)
average = (score1 + score2 + score3) / 3
print(f"平均分:{round(average, 2)}分")
函数调用流程:
2.3 Python的多态特性
Python函数的强大之处在于参数无需声明类型,支持多种数据类型:
def my_sum(a, b):
return a + b
print(my_sum(3, 5)) # 8(整数相加)
print(my_sum([1, 2], [3, 4])) # [1, 2, 3, 4](列表拼接)
print(my_sum('hello ', 'world')) # 'hello world'(字符串合并)
3. 函数参数详解:4种核心类型
3.1 位置参数
def add_num(a, b): # a和b是位置参数
return a + b
print(add_num(3, 5)) # 3传给a,5传给b,输出8
3.2 关键字参数
def calc_total(price, count, discount):
return price * count * discount
# 关键字参数调用:顺序可换
total1 = calc_total(price=100, count=5, discount=0.8)
total2 = calc_total(count=5, price=100, discount=0.8) # 顺序变了,结果一样
3.3 默认值参数
def calc_total(price, count, discount=1.0): # discount默认值1.0
return price * count * discount
total1 = calc_total(100, 5) # 使用默认折扣1.0,输出500
total2 = calc_total(100, 5, 0.8) # 覆盖默认值,输出400
3.4 可变参数(*args)
def calc_average(*args): # *args接收任意个参数,打包成元组
if len(args) == 0:
print("请传入至少1个数字")
return 0
return sum(args) / len(args)
print(calc_average(85, 92, 78)) # 输出85.0
print(calc_average(90, 88, 95, 76, 82)) # 输出86.2
参数类型选择指南:
4. 函数嵌套与作用域
4.1 函数嵌套的优势
优势1:数据隐私保护
def connect_DB():
def get_DB_configuration(): # 内部函数,外部无法访问
return host, username, password # 敏感信息不暴露
conn = connector.connect(get_DB_configuration())
return conn
# ❌ 外部无法直接调用
# get_DB_configuration() # NameError
优势2:减少重复开销
def factorial(input):
# 输入验证(只执行一次,避免递归重复检查)
if not isinstance(input, int):
raise Exception('input must be an integer.')
if input < 0:
raise Exception('input must be >= 0')
def inner_factorial(input): # 递归核心逻辑
if input <= 1:
return 1
return input * inner_factorial(input - 1)
return inner_factorial(input)
print(factorial(5)) # 120
4.2 变量作用域:局部、全局与nonlocal
# 全局变量
MIN_VALUE = 1
def validation_check():
global MIN_VALUE # 声明使用全局变量
MIN_VALUE += 1 # ✅ 可以修改
def outer():
x = "local"
def inner():
nonlocal x # 声明使用外部函数变量
x = 'nonlocal'
print("inner:", x) # nonlocal
inner()
print("outer:", x) # nonlocal(已被修改)
validation_check()
print(MIN_VALUE) # 输出: 2
outer()
变量作用域层次:
5. 闭包(Closure):函数式编程精髓
闭包是指外部函数返回内部函数,且内部函数"记住"了外部函数的变量。
def nth_power(exponent):
def exponent_of(base):
return base ** exponent # "记住"了exponent的值
return exponent_of # 返回函数对象
# 创建专用函数
square = nth_power(2) # square现在是一个计算平方的函数
cube = nth_power(3) # cube现在是一个计算立方的函数
print(square(2)) # 4 (2²)
print(cube(2)) # 8 (2³)
闭包的优势:
- 代码简洁:减少重复参数传递
- 提升性能:外部初始化工作只执行一次
- 功能强大:为装饰器(decorator)奠定基础
闭包结构解析:
6. 实战:用函数重构成绩统计程序
将"获取成绩、计算平均分、打印等级、保存文件"封装成函数:
import datetime
# 1. 获取有效成绩(带异常处理)
def get_valid_score(student_num):
while True:
try:
score = float(input(f"请输入第{student_num}个学生成绩(0-100):"))
if 0 <= score <= 100:
return score
print("错误:成绩需在0-100之间")
except ValueError:
print("错误:请输入数字(如88.5)")
# 2. 计算平均分(支持任意个成绩)
def calc_average(*scores):
if not scores:
return 0
return sum(scores) / len(scores)
# 3. 打印成绩详情
def print_score_detail(scores, average):
print("="*30)
print("学生成绩列表:", [round(s, 2) for s in scores])
print(f"平均分:{round(average, 2)}分")
for i, s in enumerate(scores, 1):
print(f"第{i}个学生成绩:{s},", end="")
if s >= 90: print("等级:A")
elif s >= 80: print("等级:B")
else: print("等级:C")
# 4. 保存成绩到文件
def save_score_to_file(scores, average):
try:
with open("score_stat.txt", "w", encoding="utf-8") as f:
time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(f"统计时间:{time_str}\n")
f.write(f"成绩列表:{[round(s,2) for s in scores]}\n")
f.write(f"平均分:{round(average,2)}分")
print("成绩已保存到score_stat.txt")
except IOError as e:
print(f"保存失败:{e}")
# 主程序
if __name__ == "__main__":
student_count = 3
scores = []
for i in range(1, student_count+1):
score = get_valid_score(i)
scores.append(score)
average = calc_average(*scores) # 拆包列表传给可变参数
print_score_detail(scores, average)
save_score_to_file(scores, average)
重构后的优势:
- 逻辑清晰:每个函数职责单一
- 易于扩展:改
student_count即可调整统计人数 - 便于调试:问题定位到具体函数
7. 新手避坑指南:5个核心原则
- 函数名"见名知意":用动词+名词组合(如
get_valid_score),别用模糊名字 - 一个函数只做一件事:避免"万能函数",否则难维护
- 参数不宜过多:超过3个参数优先用关键字参数调用
- 处理边界情况:如
calc_average处理"无参数"情况,避免报错 - 使用
if __name__ == "__main__":让函数既能被导入复用,又能单独运行
8. 递归函数与装饰器(进阶)
8.1 递归函数示例
def factorial(n):
if n == 1: # 终止条件
return 1
else:
return n * factorial(n - 1) # 递归调用
print(factorial(5)) # 输出:120
8.2 装饰器示例
def log(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log
def demo(a, b):
print(f"Result: {a + b}")
demo(3, 5)
# 输出:
# Calling function: demo
# Result: 8
总结
自定义函数是从"写代码"到"写好代码"的关键一步。通过本文的学习,你应该掌握:
- ✅ 函数的基本定义和调用方法
- ✅ 4种参数类型的灵活运用
- ✅ 变量作用域和嵌套函数的使用
- ✅ 闭包的原理和实战应用
- ✅ 函数重构的实际案例
记住:自定义函数不是"高级技巧",而是新手必备的"代码整理工具"。从现在开始,写代码前先想"这段逻辑会不会重复用",把它封装成函数,慢慢就会养成"模块化编程"的思维。
13万+

被折叠的 条评论
为什么被折叠?



