在 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 * x result = 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)) # 403202.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!