Python核心语法——函数

在 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

查看说明文档的方式:

  1. 使用 help(函数名),例如 help(circle_area_len)

  2. 在 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)) # 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!

相关推荐
linzᅟᅠ1 小时前
README
人工智能·python
瓶中怪2 小时前
ROS2 机器人软件系统
linux·c++·python·ubuntu·vmware·ros2·机器人软件开发
满怀冰雪2 小时前
22_Runnable接口源码拆解_LCEL管道语法背后_invoke_stream_batch究竟做了什么
python·batch
大气的小蜜蜂2 小时前
基于Python+Django的健身房管理系统实现:核心亮点全流程解析
开发语言·python·django
天空'之城2 小时前
Linux 系统编程 04:进程基础
linux·开发语言·进程基础
2zcode3 小时前
免费开源项目文档:基于MATLAB图像处理的药片检测与计数系统设计与实现
开发语言·图像处理·matlab
charlie1145141913 小时前
Cinux: 加载第一个内核:从 bootloader 跳进 C++
linux·开发语言·c++·嵌入式
赵民勇3 小时前
Python 协程详解与技巧总结
python
极光代码工作室3 小时前
基于YOLO目标检测的智能监控系统
python·深度学习·yolo·机器学习·计算机视觉