在 Python 编程中,函数是组织代码、实现复用、提高可读性的核心工具。无论是处理数据、控制流程,还是构建复杂系统,函数都扮演着不可或缺的角色。本文基于一套完整的 PPT 讲义,系统梳理 Python 函数的基础用法、进阶特性及类型注解,帮助读者从零到一掌握函数编程的精髓。
一、函数基础

1.1 什么是函数
函数是组织好的、可重复使用的、用来实现特定功能的代码片段。
Python 内置了大量函数,例如 input()、print()、max()、min()、len()、sum() 等,它们都是提前定义好的、可重复使用、实现特定功能的代码块。通过调用这些函数,我们可以轻松完成输入输出、数值计算等常见任务,而无需重复编写逻辑。
1.2 函数定义与调用
函数必须先定义,再调用。定义时并不会执行函数体,只有在调用时,函数体内的逻辑才会真正运行。函数体通过缩进来描述归属关系。
基本语法:
def 函数名(参数列表):
# 函数体
return 返回值
注意事项:
-
函数定义后不会自动执行,必须显式调用。
-
函数体中的代码必须缩进一致。
-
函数名应遵循命名规范(小写字母、下划线分隔)。
1.3 函数的参数与返回值

在定义函数时,可以根据业务需要指定参数和返回值。
-
形参(形式参数):函数定义时括号里的参数,只能在函数内部使用(局部变量)。
-
实参(实际参数):函数调用时传入的具体值。
示例:
def add(a, b): # a, b 为形参
return a + b
result = add(3, 5) # 3, 5 为实参
多个返回值:
Python 函数可以返回多个值,它们会被封装到一个元组中,调用时可以使用元组解包来接收。
def get_min_max(data):
return min(data), max(data)
min_val, max_val = get_min_max([1, 2, 3, 4])
1.4 函数的说明文档(Docstring)

说明文档(Docstring)是写在函数开头,用三个引号包裹的字符串,用于解释函数的功能、参数、返回值等信息,方便调用者清楚函数的具体作用及细节。
示例:
def circle_area_len(radius):
"""计算圆的面积和周长
Args:
radius (float): 圆的半径
Returns:
tuple: (面积, 周长)
"""
import math
area = math.pi * radius ** 2
circumference = 2 * math.pi * radius
return area, circumference
查看说明文档的方式:
-
使用
help(函数名),例如help(circle_area_len)。 -
在 IDE(如 PyCharm、VS Code)中,将鼠标悬浮在函数名上,会自动展示文档(推荐)。
好的文档,能让你的代码更容易理解、使用和维护!
1.5 函数的嵌套调用
嵌套调用指的是在一个函数中,又调用了另外一个函数。函数调用遵循栈结构,最后被调用的函数最先返回(LIFO------Last In First Out,后进先出)。

调用流程示意:
function_a() 开始
│
├─ 打印 "a ... before"
│
├─ 调用 function_b()
│ │
│ ├─ 打印 "b ... before"
│ │
│ ├─ 调用 function_c()
│ │ │
│ │ └─ 打印 "c ..."
│ │
│ ├─ 打印 "b ... after"
│ │
│ └─ function_b() 返回
│
├─ 打印 "a ... after"
│
└─ function_a() 返回
这种层层调用的机制使得程序逻辑清晰,但需要注意递归深度和调用栈溢出问题。
1.6 案例
需求1: 根据传入的底和高计算三角形面积(面积 = 底 × 高 / 2)。
def triangle_area(base, height):
"""计算三角形面积"""
return base * height / 2
# 调用示例
print(triangle_area(5, 10)) # 输出 25.0
需求2: 计算传入字符串中元音字母的个数(元音字母为 aeiouAEIOU)。
def count_vowels(s: str) -> int:
"""返回字符串中元音字母的个数"""
vowels = 'aeiouAEIOU'
count = 0
for ch in s:
if ch in vowels:
count += 1
return count
# 调用示例
print(count_vowels("Hello World")) # 输出 3(e, o, o)
-
def是 Python 中定义函数的关键字。 -
count_vowels是函数名,通常见名知意("计算元音")。 -
(s: str)表示函数接受一个参数s,并且通过类型注解提示s应该是一个字符串(str),但这只是一个提示,并不会强制检查,传入其他类型也能运行,但可能出错。 -
-> int表示函数返回值期望是一个整数(int),同样只是类型提示
需求3: 计算传入班级学员高考成绩列表中的最高分、最低分、平均分(保留1位小数),并返回。
def score_stats(scores: list) -> tuple:
"""返回 (最高分, 最低分, 平均分)"""
if not scores:
return None, None, None
max_score = max(scores)
min_score = min(scores)
avg_score = round(sum(scores) / len(scores), 1)
return max_score, min_score, avg_score
# 调用示例
grades = [98, 76, 88, 92, 65, 79]
max_s, min_s, avg_s = score_stats(grades)
print(f"最高: {max_s}, 最低: {min_s}, 平均: {avg_s}")
二、函数进阶
2.1 函数变量的作用域
变量的作用域指的是变量在程序中可以被访问的范围。
-
全局变量:在函数外部声明的变量,可以在整个模块中访问。
-
局部变量:在函数内部定义的变量,只能在函数内部使用。
global 关键字:用于明确告诉 Python 解释器,在函数中要使用全局变量,从而可以在函数内部修改全局变量的值。
num1 = 10
def modify():
global num1 # 声明使用全局变量 num1
num1 = 20
注意事项:
-
尽量避免在函数中使用全局变量,因为会使代码难以维护和调试。
-
推荐使用函数参数和返回值来传递数据,而不是依赖全局变量。
-
global主要用在程序的状态管理、配置和计数器等场景中。
2.2 函数参数详解
2.2.1 传参方式
① 位置参数:调用函数时,传入实参的顺序与定义函数时形参的顺序完全一致。
def calc(math, chinese, english, computer):
return math + chinese + english + computer
s = calc(87, 68, 92, 85) # 位置参数
优点 :简洁;缺点 :可读性差、易出错、维护难。
适用场景:参数较少(不超过3个),且顺序自然。
② 关键字参数 :调用函数时以形参名作为关键字,以 键=值 的形式传递参数,不要求顺序。
s = calc(math=87, chinese=68, english=92, computer=85)
优点 :可读性强、易维护和扩展;缺点 :代码稍显繁琐。
适用场景:参数较多,或参数含义易混淆的场景。
混合使用 :如果同时存在位置参数与关键字参数,关键字参数必须在位置参数之后(关键字参数之间没有顺序要求)。
黄金法则:半年后回头看你今天写的代码,能否一眼看出每个参数的含义,如果不能,就应该使用关键字参数。
2.2.2 默认参数
默认参数(缺省参数)在定义函数时为参数提供默认值,调用时可以不传递这些参数。
def greet(name, msg="Hello"):
print(f"{msg}, {name}")
greet("Alice") # 使用默认 msg
greet("Bob", "Hi") # 覆盖默认值
默认参数通常放在参数列表的末尾,避免歧义。
2.2.3 不定长参数
当参数个数不确定时,可以使用不定长参数(可变参数)。
① 位置传递(*args):将多个位置参数封装成一个元组(tuple)。
def calc_data(*args):
return min(args), max(args), sum(args)/len(args)
min_v, max_v, avg_v = calc_data(389, 39, 29, 105)
② 关键字传递(**kwargs):将多个关键字参数封装成一个字典(dict)。
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Tom", age=18, city="Beijing")
应用场景:
-
*args适用于处理数量不确定的数据序列。 -
**kwargs适用于处理数量不确定的选项或配置参数,用来定制函数行为。
2.2.4 参数类型
函数参数可以是任何 Python 对象:
-
普通参数:数字、布尔、字符串、列表、元组、集合、字典等。
-
特殊参数:函数本身(即函数可以作为参数传递,这为高阶函数和回调机制提供了可能)。
def apply(func, value):
return func(value)def square(x):
return x * xresult = apply(square, 5) # 传递函数作为参数
2.3 匿名函数(lambda 表达式)

匿名函数是没有名称的函数,通过 lambda 表达式声明,适用于简单函数的快速定义(单行表达式)。
语法:
lambda 参数列表 : 函数体
示例:
# 定义一个无参匿名函数
lambda: print('-------------------------')
# 定义两个参数的加法
add = lambda x, y: x + y
print(add(3, 5)) # 输出 8
命名函数 vs 匿名函数:
-
使用匿名函数 :逻辑简单,只在一个地方调用(常作为高阶函数的参数),例如
sorted(iterable, key=lambda x: x[1])。 -
使用命名函数:逻辑复杂,需要多步操作,需要多个地方重复使用或需要文档说明的场景。
代码的可读性和可维护性比简洁性更重要,请合理选择。
2.4 案例2:综合练习
2.4.1 阶乘计算
定义函数,根据传入数字计算该数字的阶乘。
分析:
-
8 的阶乘 = 8 × 7 × 6 × 5 × 4 × 3 × 2 × 1
-
递推公式:f(n) = n × f(n-1),其中 f(1) = 1。
def factorial(n: int) -> int:
"""递归计算 n 的阶乘"""
if n < 0:
raise ValueError("n 必须为非负整数")
if n == 0 or n == 1:
return 1
return n * factorial(n - 1)调用示例
print(factorial(5)) # 120
print(factorial(8)) # 40320
2.4.2 班级成绩统计
根据输入的班级名称以及各个学员的考试总分,统计班级的平均分,以及高于平均分和低于平均分的人数。
def class_stats(class_name: str, scores: list) -> dict:
"""
统计班级成绩信息
:param class_name: 班级名称
:param scores: 学员总分列表
:return: 包含统计结果的字典
"""
if not scores:
return {
"班级": class_name,
"平均分": None,
"高于平均分人数": 0,
"低于平均分人数": 0
}
avg = sum(scores) / len(scores)
above = sum(1 for s in scores if s > avg)
below = sum(1 for s in scores if s < avg)
# 等于平均分的人数忽略(不算高也不算低)
return {
"班级": class_name,
"平均分": round(avg, 2),
"高于平均分人数": above,
"低于平均分人数": below
}
# 调用示例
result = class_stats("高三(1)班", [580, 620, 540, 590, 610, 550])
print(result)
# 输出:{'班级': '高三(1)班', '平均分': 581.67, '高于平均分人数': 3, '低于平均分人数': 3}
2.4.3 电商订单计算器
定义一个函数,根据传入的商品信息(商品名、价格、数量)、优惠(优惠券、积分抵扣)和运费信息计算订单总金额。
规则:
-
优惠券需要商品金额满 5000 才可使用,且优惠券金额不能超过商品总价。
-
积分抵扣需要商品总金额满 5000 才可使用,100 积分抵扣 1 元(抵扣金额不能超过商品总价,积分只能整百抵扣)。
def calculate_order(
items: list, # 每个元素为 (商品名, 单价, 数量)
coupon: float = 0.0, # 优惠券金额
points: int = 0, # 可用积分
shipping: float = 0.0 # 运费
) -> dict:
"""
计算订单最终金额
:return: 包含各项明细的字典
"""
# 计算商品总价
total_goods = sum(price * qty for _, price, qty in items)
# 初始折扣
discount = 0.0
# 处理优惠券
if total_goods >= 5000 and coupon > 0:
discount = min(coupon, total_goods) # 不能超过商品总价
# 处理积分抵扣
points_discount = 0.0
if total_goods >= 5000 and points >= 100:
# 整百积分,每100积分抵扣1元
usable_points = (points // 100) * 100
points_discount = usable_points / 100
# 抵扣金额不能超过商品总价扣除优惠券后的金额
max_discount = total_goods - discount
if points_discount > max_discount:
points_discount = max_discount
# 最终支付金额
final_total = total_goods - discount - points_discount + shipping
return {
"商品总价": round(total_goods, 2),
"优惠券抵扣": round(discount, 2),
"积分抵扣": round(points_discount, 2),
"运费": round(shipping, 2),
"实付金额": round(final_total, 2)
}调用示例
items = [("手机", 2999, 2), ("耳机", 199, 1)] # 总价 6197
result = calculate_order(items, coupon=200, points=1500, shipping=10)
print(result)输出示例:{'商品总价': 6197.0, '优惠券抵扣': 200.0, '积分抵扣': 15.0, '运费': 10.0, '实付金额': 5992.0}
2.4.4 列表推导式与生成器表达式对比
列表推导式:
[要插入的值 for i in 数据集 if 条件]
-
特点:立即求值,一次性生成整个列表并存入内存,占用内存空间大。
-
场景:数据量不大,需要全部立即生成的场景;需要重复使用、多次访问的场景。
生成器表达式:
(要插入的值 for i in 数据集 if 条件)
-
特点:惰性求值,按需逐个生成元素,无需同时存储所有元素,节省内存。
-
场景 :处理大数据集,避免一次性加载所有数据到内存;常用于
sum()、max()、min()等函数的参数。
完整对比示例:
import sys
# 列表推导式 - 立刻生成全部数据,占用内存
squares_list = [x**2 for x in range(1000000)]
print(f"列表推导式占用内存:{sys.getsizeof(squares_list)} 字节") # 约 8MB
# 生成器表达式 - 惰性求值,仅存储生成器对象本身
squares_gen = (x**2 for x in range(1000000))
print(f"生成器表达式占用内存:{sys.getsizeof(squares_gen)} 字节") # 非常小
# 使用生成器作为 sum 的参数,边生成边累加,内存友好
total = sum(x**2 for x in range(1000000)) # 无需额外存储列表
print(f"总和:{total}")
# 当需要多次遍历时,列表更合适(生成器只能迭代一次)
# 列表可以重复使用
my_list = [x*2 for x in range(10)]
print(sum(my_list)) # 可以多次使用
print(max(my_list))
三、类型注解
3.1 基本介绍
类型注解是 Python 中的一种语法特性,用于明确标识变量、函数参数和返回值的数据类型,从而使代码更清晰、更安全、更易维护。
类型推断是指 Python 解释器自动推断出变量、表达式或函数返回值的数据类型的能力,而无需开发者显式声明。
类型注解的写法:
变量名: 数据类型 = 值
例如:
a: int = 10
name: str = "Alice"
data: list[int] = [1, 2, 3]
mixed: str | int = "hello" # Python 3.10+ 支持联合类型
为什么要使用类型注解?
-
代码结构更清晰、逻辑更安全、易维护。
-
更准确的代码自动提示(IDE 支持)。
-
提前发现代码潜在问题(借助静态检查工具如 mypy)。
注意:Python 是动态类型语言,添加的类型注解只是提示,并不是强制约束!
3.2 函数类型注解
为函数添加类型注解,主要针对参数和返回值:
语法:
def 函数名(参数名: 类型, ...) -> 返回值类型:
...
示例:
def calculate_total(
items: list[tuple[str, float, int]], # 商品列表:[(名称, 单价, 数量)]
coupon: float = 0.0, # 优惠券金额
points: int = 0 # 积分
) -> float: # 返回总金额
total = sum(price * qty for _, price, qty in items)
# 应用优惠逻辑...
return total
综合案例:电商订单计算器(含类型注解)
定义一个函数,根据传入的商品信息、优惠和运费计算购物车总金额,规则同上(满 5000 可用优惠券和积分抵扣)。
为函数添加合理的类型注解,可以极大提升代码的可读性和团队协作效率。
from typing import List, Tuple, Dict
def calculate_order_typed(
items: List[Tuple[str, float, int]], # [(名称, 单价, 数量)]
coupon: float = 0.0,
points: int = 0,
shipping: float = 0.0
) -> Dict[str, float]:
"""带类型注解的订单计算器"""
total_goods = sum(price * qty for _, price, qty in items)
discount = 0.0
if total_goods >= 5000 and coupon > 0:
discount = min(coupon, total_goods)
points_discount = 0.0
if total_goods >= 5000 and points >= 100:
usable_points = (points // 100) * 100
points_discount = usable_points / 100
max_discount = total_goods - discount
if points_discount > max_discount:
points_discount = max_discount
final_total = total_goods - discount - points_discount + shipping
return {
"商品总价": round(total_goods, 2),
"优惠券抵扣": round(discount, 2),
"积分抵扣": round(points_discount, 2),
"运费": round(shipping, 2),
"实付金额": round(final_total, 2)
}
对于需要团队协作开发和长期维护的项目,推荐使用类型注解。
四、结语
函数是 Python 编程的核心构建块。从基础的参数传递到进阶的作用域、匿名函数,再到现代化的类型注解,掌握这些知识将帮助你写出更优雅、更健壮、更易维护的代码。
希望本文的梳理能为你提供一份实用的参考手册。动手实践每个案例,你会发现函数编程的魅力和力量。Happy Coding!