定义与调用函数
函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码块。Python 中的函数通过 def 关键字定义,它能够接收输入参数、执行逻辑并返回结果。掌握函数的定义与调用是编写可维护、可复用代码的基础。
def 语法
Python 使用 def 关键字定义函数,基本语法如下:
def 函数名(参数列表):
"""文档字符串(可选)"""
函数体
return 返回值
一个最简单的例子:
def greet():
"""打印问候语"""
print("你好,Python!")
greet()
# 输出:你好,Python!
带参数的函数:
def greet(name):
print(f"你好,{name}!")
greet("小明")
# 输出:你好,小明!
return 返回值
return 语句用于从函数中返回结果。函数可以没有 return,也可以返回单个值或多个值。
返回单个值
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 输出:8
返回多个值(元组解包)
Python 允许函数返回多个值,实际上是返回一个元组,再通过解包赋值给多个变量:
def min_max(numbers):
return min(numbers), max(numbers)
data = [3, 1, 4, 1, 5, 9, 2, 6]
low, high = min_max(data)
print(f"最小值:{low},最大值:{high}")
# 输出:最小值:1,最大值:9
:::tip 元组解包 返回多个值时,Python 实际上是返回一个元组。下面的两种写法等价:
result = min_max(data) # result 是 (1, 9)
low, high = min_max(data) # 通过解包分别赋值
:::
提前 return
函数中可以有多条 return 语句,遇到第一条就立即结束函数:
def check_age(age):
if age < 0:
return "年龄不能为负数"
if age >= 18:
return "成年人"
return "未成年人"
print(check_age(20)) # 输出:成年人
print(check_age(10)) # 输出:未成年人
print(check_age(-1)) # 输出:年龄不能为负数
无返回值(None)
如果函数没有 return 语句,或者 return 后没有跟任何值,函数会返回 None:
def say_hello(name):
print(f"Hello, {name}")
result = say_hello("Tom")
print(result) # 输出:None
print(type(result)) # 输出:<class 'NoneType'>
显式返回 None:
def find_first_even(numbers):
for n in numbers:
if n % 2 == 0:
return n
return None # 没找到偶数时返回 None
print(find_first_even([1, 3, 5, 6])) # 输出:6
print(find_first_even([1, 3, 5])) # 输出:None
:::warning 检查 None
判断函数是否返回 None 时,应使用 is None 而不是 == None:
if result is None:
print("未找到")
这是因为 == 会调用对象的 __eq__ 方法,可能在某些自定义对象上产生意外行为。
:::
文档字符串
文档字符串(docstring)是放在函数体第一行的字符串,用于说明函数的用途、参数和返回值。Python 内置的 help() 和 IDE 的提示都会读取它。
def calculate_bmi(weight, height):
"""计算身体质量指数 BMI。
参数:
weight: 体重,单位千克
height: 身高,单位米
返回:
BMI 值,保留一位小数
"""
bmi = weight / (height ** 2)
return round(bmi, 1)
print(calculate_bmi(70, 1.75)) # 输出:22.9
help(calculate_bmi)
常见的文档字符串风格有 Google 风格、NumPy 风格和 reStructuredText 风格。下面是 Google 风格示例:
def fetch_data(url, timeout=10):
"""从指定 URL 获取数据。
Args:
url: 请求的目标 URL。
timeout: 超时时间(秒),默认 10。
Returns:
字典形式的数据。
Raises:
TimeoutError: 当请求超时时抛出。
"""
...
:::info 查看文档字符串
除了 help(func),你也可以通过 func.__doc__ 直接访问文档字符串:
print(calculate_bmi.__doc__)
:::
函数是一等公民
在 Python 中,函数是一等公民(first-class citizen),这意味着函数可以:
- 赋值给变量
- 作为参数传递给另一个函数
- 作为函数的返回值
- 存储在数据结构中
赋值给变量
def shout(text):
return text.upper()
yell = shout # 将函数赋值给变量
print(yell("hello")) # 输出:HELLO
函数作为参数
函数可以作为参数传递给另一个函数,这是高阶函数的核心:
def apply(func, value):
"""对 value 应用 func 函数"""
return func(value)
def double(x):
return x * 2
def square(x):
return x ** 2
print(apply(double, 5)) # 输出:10
print(apply(square, 5)) # 输出:25
函数作为返回值
函数也可以作为另一个函数的返回值:
def make_multiplier(factor):
"""返回一个将参数乘以 factor 的函数"""
def multiplier(x):
return x * factor
return multiplier
times3 = make_multiplier(3)
times5 = make_multiplier(5)
print(times3(10)) # 输出:30
print(times5(10)) # 输出:50
存储在数据结构中
operations = {
"add": lambda a, b: a + b,
"sub": lambda a, b: a - b,
"mul": lambda a, b: a * b,
}
print(operations["add"](3, 4)) # 输出:7
print(operations["mul"](3, 4)) # 输出:12
内置函数简介
Python 提供了大量内置函数,可以直接使用而无需导入。常用的包括:
# 数学相关
print(abs(-5)) # 输出:5
print(max(1, 2, 3)) # 输出:3
print(min(1, 2, 3)) # 输出:1
print(round(3.14159, 2)) # 输出:3.14
print(pow(2, 10)) # 输出:1024
# 类型转换
print(int("42")) # 输出:42
print(float("3.14")) # 输出:3.14
print(str(42)) # 输出:"42"
print(list("abc")) # 输出:['a', 'b', 'c']
# 序列操作
print(len([1, 2, 3])) # 输出:3
print(sorted([3, 1, 2])) # 输出:[1, 2, 3]
print(sum([1, 2, 3])) # 输出:6
print(any([False, True])) # 输出:True
print(all([True, True])) # 输出:True
# 迭代相关
print(list(range(5))) # 输出:[0, 1, 2, 3, 4]
print(list(enumerate("ab"))) # 输出:[(0, 'a'), (1, 'b')]
print(list(zip([1, 2], ["a", "b"]))) # 输出:[(1, 'a'), (2, 'b')]
:::tip 查看所有内置函数 使用以下代码查看 Python 提供的所有内置函数和常量:
print(dir(__builtins__))
:::
类型注解基础
Python 3.5+ 引入了类型注解(type hints),它不会影响运行时行为,但能让代码更易读,并配合工具(如 mypy)进行静态类型检查。
参数与返回值标注
def add(a: int, b: int) -> int:
"""两个整数相加"""
return a + b
def greet(name: str) -> str:
"""返回问候字符串"""
return f"你好,{name}"
print(add(3, 5)) # 输出:8
print(greet("小明")) # 输出:你好,小明
复杂类型注解
对于列表、字典等容器类型,Python 3.9+ 允许直接使用内置类型进行注解:
def average(numbers: list[float]) -> float:
"""计算平均值"""
return sum(numbers) / len(numbers)
def count_words(text: str) -> dict[str, int]:
"""统计每个单词出现次数"""
words = text.split()
result: dict[str, int] = {}
for word in words:
result[word] = result.get(word, 0) + 1
return result
print(average([1.0, 2.0, 3.0])) # 输出:2.0
print(count_words("hello world hello"))
# 输出:{'hello': 2, 'world': 1}
:::info 类型注解不会强制检查 类型注解只是"提示",Python 解释器不会在运行时检查类型。下面的代码也能正常运行:
def add(a: int, b: int) -> int:
return a + b
print(add("hello", " world")) # 输出:hello world
要获得类型检查能力,需要使用 mypy 等静态类型检查工具。 :::
可选类型与联合类型
Python 3.10+ 支持使用 | 表示联合类型,X | None 等价于 Optional[X]:
def find_user(user_id: int) -> dict | None:
"""查找用户,找不到返回 None"""
users = {1: {"name": "Alice"}, 2: {"name": "Bob"}}
return users.get(user_id)
print(find_user(1)) # 输出:{'name': 'Alice'}
print(find_user(3)) # 输出:None
实战:简易计算器
下面通过一个简易计算器综合运用函数定义、返回值、文档字符串和类型注解:
def calculator(a: float, b: float, op: str) -> float | str:
"""简易计算器。
Args:
a: 第一个操作数
b: 第二个操作数
op: 运算符,支持 + - * /
Returns:
计算结果;若运算符不支持,返回错误信息字符串
"""
operations = {
"+": lambda x, y: x + y,
"-": lambda x, y: x - y,
"*": lambda x, y: x * y,
"/": lambda x, y: x / y if y != 0 else "错误:除数不能为零",
}
if op not in operations:
return f"错误:不支持的运算符 {op}"
result = operations[op](a, b)
return result
def main():
"""主循环:读取用户输入并输出结果"""
print("简易计算器(输入 q 退出)")
while True:
expr = input(">>> ").strip()
if expr.lower() == "q":
print("再见!")
break
parts = expr.split()
if len(parts) != 3:
print("格式:数字 运算符 数字,例如 3 + 5")
continue
try:
a, op, b = float(parts[0]), parts[1], float(parts[2])
except ValueError:
print("请输入合法的数字")
continue
result = calculator(a, b, op)
print(f"= {result}")
if __name__ == "__main__":
main()
运行示例:
简易计算器(输入 q 退出)
>>> 3 + 5
= 8.0
>>> 10 / 4
= 2.5
>>> 10 / 0
= 错误:除数不能为零
>>> q
再见!
:::tip if name == "main"
if __name__ == "__main__": 是 Python 的惯用写法,确保该代码块只在直接运行脚本时执行,被其他模块导入时不会执行。这对于可复用模块非常重要。
:::
小结
- 使用
def定义函数,通过函数名加括号调用 return用于返回值,可返回单个值或多个值(元组解包)- 没有
return或return后无值时,函数返回None - 文档字符串用于说明函数用途,可通过
help()查看 - Python 中函数是一等公民,可赋值、传参、作为返回值和存储在容器中
- 类型注解让代码更易读、便于静态检查,但不影响运行时行为
- 合理使用内置函数能大幅简化代码
掌握函数的定义和调用之后,下一节将深入讲解函数的参数机制,包括位置参数、关键字参数、默认值、可变参数等灵活用法。