函数基础
学习目标
- 理解函数是什么,为什么需要函数
- 掌握函数的定义和调用
- 理解参数(位置参数、默认参数、关键字参数)
- 掌握返回值的使用
- 理解变量作用域
为什么需要函数?
假设你在写一个数据处理脚本,需要多次计算平均值:
# 第一次计算
scores1 = [85, 92, 78, 95, 88]
total1 = sum(scores1)
avg1 = total1 / len(scores1)
print(f"平均分: {avg1:.1f}")
# 第二次计算(又写一遍一模一样的逻辑)
scores2 = [90, 85, 92, 88, 95, 87]
total2 = sum(scores2)
avg2 = total2 / len(scores2)
print(f"平均分: {avg2:.1f}")
# 第三次计算(再写一遍……)
scores3 = [75, 80, 68, 72, 88]
total3 = sum(scores3)
avg3 = total3 / len(scores3)
print(f"平均分: {avg3:.1f}")
同样的逻辑写了 3 遍——如果以后要改计算方式(比如去掉最高最低分),你得改 3 个地方。
用函数解决:
def calculate_average(scores):
"""计算平均分"""
return sum(scores) / len(scores)
# 现在一行搞定
print(f"平均分: {calculate_average([85, 92, 78, 95, 88]):.1f}")
print(f"平均分: {calculate_average([90, 85, 92, 88, 95, 87]):.1f}")
print(f"平均分: {calculate_average([75, 80, 68, 72, 88]):.1f}")
函数的核心价值:
| 好处 | 说明 |
|---|---|
| 复用 | 写一次,用多次 |
| 抽象 | 把复杂逻辑藏在函数名后面,调用时只需要知道"做什么",不用管"怎么做" |
| 维护 | 要改逻辑只改一个地方 |
| 可读 | 函数名就是注释,calculate_average(scores) 一目了然 |
定义和调用函数
基本语法
def greet(name):
"""向某人打招呼""" # 文档字符串(docstring),描述函数做什么
print(f"你好,{name}!欢迎学习 Python!")
# 调用函数
greet("小明") # 你好,小明!欢迎学习 Python!
greet("小红") # 你好,小红!欢迎学习 Python!
语法解读:
def关键字表示"定义一个函数"greet是函数名(命名规则和变量一样,小写加下划线)(name)是参数列表:冒号不能忘- 函数体需要缩进
"""..."""是文档字符串,描述函数的功能
没有参数的函数
def say_hello():
print("Hello, World!")
say_hello() # Hello, World!
多个参数的函数
def add(a, b):
result = a + b
print(f"{a} + {b} = {result}")
add(3, 5) # 3 + 5 = 8
add(10, 20) # 10 + 20 = 30
返回值
函数可以用 return 把结果返回给调用者:
def add(a, b):
return a + b
# 函数的返回值可以赋给变量
result = add(3, 5)
print(result) # 8
# 也可以直接使用返回值
print(add(10, 20)) # 30
# 在表达式中使用
total = add(1, 2) + add(3, 4)
print(total) # 10
返回多个值
def get_min_max(numbers):
"""返回列表中的最小值和最大值"""
return min(numbers), max(numbers)
# 用元组解包接收
smallest, largest = get_min_max([3, 1, 4, 1, 5, 9])
print(f"最小值: {smallest}, 最大值: {largest}")
# 最小值: 1, 最大值: 9
没有 return 的函数
如果函数没有 return 语句,或者 return 后面没有值,函数返回 None:
def greet(name):
print(f"你好,{name}!")
# 没有 return
result = greet("小明") # 打印: 你好,小明!
print(result) # None
return 的另一个用途:提前结束函数
def divide(a, b):
if b == 0:
print("错误:除数不能为 0!")
return None # 提前结束函数
return a / b
print(divide(10, 3)) # 3.333...
print(divide(10, 0)) # 错误:除数不能为 0! 然后返回 None
参数详解
位置参数
按照顺序传入的参数:
def describe_pet(animal, name):
print(f"我有一只{animal},名叫{name}")
describe_pet("猫", "咪咪") # 我有一只猫,名叫咪咪
describe_pet("咪咪", "猫") # 我有一只咪咪,名叫猫 —— 顺序错了!
关键字参数
通过参数名传值,不用在乎顺序:
def describe_pet(animal, name):
print(f"我有一只{animal},名叫{name}")
# 用关键字参数,顺序无所谓
describe_pet(name="咪咪", animal="猫") # 我有一只猫,名叫咪咪
describe_pet(animal="狗", name="旺财") # 我有一只狗,名叫旺财
默认参数
给参数一个默认值,调用时可以不传:
def train_model(epochs=10, lr=0.001, batch_size=32):
print(f"训练参数: epochs={epochs}, lr={lr}, batch_size={batch_size}")
# 使用全部默认值
train_model()
# 训练参数: epochs=10, lr=0.001, batch_size=32
# 只修改部分参数
train_model(epochs=50)
# 训练参数: epochs=50, lr=0.001, batch_size=32
train_model(epochs=100, lr=0.01)
# 训练参数: epochs=100, lr=0.01, batch_size=32
默认参数的陷阱
默认参数的值在函数定义时就确定了。不要用可变对象(如列表、字典)作为默认值:
# 错误做法 ❌
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("a")) # ['a']
print(add_item("b")) # ['a', 'b'] —— 出bug了!上次的 'a' 还在
# 正确做法 ✅
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items