python的函数

2025/10/10 python

# 1.概述

函数是Python中最重要的代码组织方式之一,它将一组语句组织在一起,以完成特定任务。函数提供了代码重用、模块化和可维护性的核心机制。

# 2.核心概念

# 2.1.为什么使用函数?

优势 描述 示例
代码重用 避免重复编写相同的代码 计算面积的函数可以在多处使用
模块化 将复杂问题分解为小问题 将数据处理分为读取、处理、输出三个函数
可维护性 更容易调试和修改 修改函数内部逻辑,所有调用处自动更新
可读性 使代码更易于理解 有意义的函数名让代码自文档化

# 2.2.函数的基本结构

def function_name(parameters):
    """文档字符串(可选)"""
    # 函数体
    return value  # 可选
1
2
3
4

组成部分

  • 函数名:标识函数的名称,遵循变量命名规则
  • 参数列表:括号中的变量名,表示调用时可以传递的值
  • 函数体:缩进的代码块,包含具体的实现逻辑
  • 返回值:通过return语句将结果返回给调用者

# 3.定义和调用函数

# 3.1.基本函数定义

# 返回平方
def square(x):
    return x * x

print(square(4))  # 16
print(square(9))  # 81

# 不带参数和返回值的函数
def say_hello():
    print("Hello from function!")

say_hello()  # Hello from function!
1
2
3
4
5
6
7
8
9
10
11
12

# 3.2.函数体缩进规则

Python要求函数体代码必须缩进(通常为4个空格),否则会报错:

def foo():
    print("这是函数体")  # 正确缩进

# 错误写法:
# def bar():
# print("没有缩进,Python会报错")
1
2
3
4
5
6

# 3.3.文档字符串

可以在函数内部定义文档字符串(docstring),用于描述函数的作用:

def greet(name):
    """向指定的人打招呼"""
    print(f"Hello, {name}!")

# 查看文档字符串
print(greet.__doc__)  # 向指定的人打招呼
1
2
3
4
5
6

# 3.4.带参数的函数

def greet(name):
    print(f"Hello, {name}!")

greet("Alice")  # Hello, Alice!
greet("Bob")    # Hello, Bob!
1
2
3
4
5

# 3.5.带返回值的函数

def add(a, b):
    return a + b

result = add(3, 5)
print(result)  # 8
1
2
3
4
5

# 4.参数类型详解

# 4.1.位置参数(Positional Arguments)

位置参数是最基本的参数类型,调用函数时按照参数的位置一一对应传递。

def add(a, b):
    print(f"a={a}, b={b}")
    return a + b

result = add(2, 3)  # a=2, b=3
print(result)  # 5
1
2
3
4
5
6

特点

  • 参数的顺序很重要,不能颠倒
  • 调用时必须提供所有必需参数
  • 参数按位置顺序赋值

# 4.2.关键字参数(Keyword Arguments)

关键字参数允许你在调用函数时,通过"参数名=值"的形式传递参数,这样参数顺序就可以任意。

def student_info(name, age, city):
    print(f"姓名: {name}, 年龄: {age}, 城市: {city}")

# 使用关键字参数,参数顺序可以不按定义顺序
student_info(age=20, name='Lucy', city='Beijing')
# 输出:姓名: Lucy, 年龄: 20, 城市: Beijing
1
2
3
4
5
6

优点

  • 不用记住参数顺序
  • 增加代码可读性
  • 很适合带有默认参数的函数

# 4.3.默认参数(Default Arguments)

默认参数是指在定义函数时为参数提供默认值。在调用函数时,如果对应参数没有传值,则会使用这个默认值。

def greet(name, msg='Hello'):
    print(f"{msg}, {name}!")

greet('Alice')            # 输出:Hello, Alice!
greet('Bob', msg='Hi')    # 输出:Hi, Bob!
1
2
3
4
5

注意事项

  • 默认参数必须出现在非默认参数之后
  • 默认参数常用于大多数情况下使用同一个值的场景
# 错误示例
def foo(a=1, b):  # 会报错
    pass

# 正确写法
def foo(a, b=1):
    pass
1
2
3
4
5
6
7

# 4.4.可变参数 (*args)

可变参数用于当函数需要接受不定数量的位置参数时,通过在参数前加*来实现。

def show_args(*args):
    print(f"参数类型: {type(args)}")
    print(f"参数内容: {args}")

show_args(1, 2, 3)        # 参数类型: <class 'tuple'>
                          # 参数内容: (1, 2, 3)
show_args('a', 'b', 'c')  # 参数类型: <class 'tuple'>
                          # 参数内容: ('a', 'b', 'c')
1
2
3
4
5
6
7
8

特点

  • *args不是必须叫args,但习惯上都叫args
  • 所有传入的位置参数被收集到一个元组中
  • 特别适合参数数量不确定时使用

实际应用

def make_pizza(*toppings):
    print("制作一个披萨,添加以下配料:")
    for topping in toppings:
        print(f"- {topping}")

make_pizza('意大利香肠')
make_pizza('蘑菇', '青椒', '芝士')
1
2
3
4
5
6
7

# 4.5.关键字可变参数 (**kwargs)

关键字可变参数允许函数接收任意数量的"关键字参数"。这些参数会被自动收集到一个字典中。

def show_kwargs(**kwargs):
    print(f"参数类型: {type(kwargs)}")
    print(f"参数内容: {kwargs}")

show_kwargs(a=1, b=2, c=3)  # 参数类型: <class 'dict'>
                           # 参数内容: {'a': 1, 'b': 2, 'c': 3}
1
2
3
4
5
6

特点

  • **kwargs不是必须叫kwargs,习惯上都这么命名
  • 多余的关键字参数汇集到一个字典里
  • 常用于不确定会传入哪些命名参数时

综合示例

def demo(a, *args, b=1, **kwargs):
    print(f"a: {a}")
    print(f"args: {args}")
    print(f"b: {b}")
    print(f"kwargs: {kwargs}")

demo(100, 2, 3, x=4, y=5)
# 输出:
# a: 100
# args: (2, 3)
# b: 1
# kwargs: {'x': 4, 'y': 5}
1
2
3
4
5
6
7
8
9
10
11
12

# 4.6.参数解包

在Python中,***不仅可以用于函数定义时接收可变参数,还可以用于参数解包

# 4.6.1.* 用于解包序列类型

def greet(name, age, city):
    print(f"姓名: {name}, 年龄: {age}, 城市: {city}")

# 使用 * 解包列表
person_info = ["Alice", 25, "北京"]
greet(*person_info)  # 等同于 greet("Alice", 25, "北京")

# 使用 * 解包元组
data = ("Bob", 30, "上海")
greet(*data)  # 等同于 greet("Bob", 30, "上海")
1
2
3
4
5
6
7
8
9
10

# 4.6.2.** 用于解包字典类型

def create_profile(name, age, city, occupation):
    print(f"姓名: {name}, 年龄: {age}, 城市: {city}, 职业: {occupation}")

# 使用 ** 解包字典
profile_data = {
    "name": "Charlie",
    "age": 28,
    "city": "广州",
    "occupation": "工程师"
}
create_profile(**profile_data)
1
2
3
4
5
6
7
8
9
10
11

# 4.6.3.混合使用 * 和 **

def complex_function(a, b, c, d, e):
    print(f"a={a}, b={b}, c={c}, d={d}, e={e}")

# 位置参数列表
positional_args = [1, 2]
# 关键字参数字典
keyword_args = {"d": 4, "e": 5}

# 混合解包
complex_function(*positional_args, 3, **keyword_args)
# 等同于 complex_function(1, 2, 3, d=4, e=5)
1
2
3
4
5
6
7
8
9
10
11

# 5.返回值详解

# 5.1.返回单个值

def get_formatted_name(first_name, last_name):
    full_name = f"{first_name}{last_name}"
    return full_name

musician = get_formatted_name('张', '三')
print(musician)  # 张三
1
2
3
4
5
6

# 5.2.返回多个值

def operate_numbers(a, b):
    sum_result = a + b
    diff_result = a - b
    product_result = a * b
    return sum_result, diff_result, product_result

# 接收元组
result = operate_numbers(10, 5)
print(result)  # (15, 5, 50)

# 解包返回值
sum_val, diff_val, product_val = operate_numbers(10, 5)
print(f"Sum: {sum_val}, Difference: {diff_val}, Product: {product_val}")
1
2
3
4
5
6
7
8
9
10
11
12
13

# 5.3.返回复杂数据结构

def create_student_report(name, **scores):
    report = {
        'name': name,
        'total_score': 0,
        'subjects': scores
    }

    # 计算总分
    for score in scores.values():
        report['total_score'] += score

    # 计算平均分
    report['average'] = report['total_score'] / len(scores)
    return report

student = create_student_report('Alice', math=95, science=87, english=92)
print(student)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 6.函数文档和注释

# 6.1.文档字符串(Docstring)

文档字符串是紧跟在函数定义后,用三引号包裹的字符串,用于描述函数的用途、参数说明、返回值类型等。

def calculate_circle_area(radius):
    """
    计算圆的面积

    参数:
    radius (float): 圆的半径

    返回:
    float: 圆的面积
    """
    import math
    return math.pi * radius ** 2

# 查看文档字符串
print(calculate_circle_area.__doc__)
# 查看函数帮助
help(calculate_circle_area)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 6.2.注释

注释是用#开头的说明性文字,用于解释代码片段的实现思路、注意事项或特殊用途。

def safe_divide(a, b):
    """安全的除法函数"""
    # 检查除数是否为零
    if b == 0:
        return "错误:除数不能为零"

    # 执行除法运算
    result = a / b
    return result
1
2
3
4
5
6
7
8
9

# 7.变量作用域

# 7.1.作用域类型

Python中的变量作用域有以下几种:

作用域类型 描述 示例
局部作用域 变量在函数内部定义,只能在该函数内部使用 函数内的局部变量
全局作用域 变量在所有函数体外部定义,可以在整个模块里访问 模块级别的变量
嵌套作用域 内部函数可以访问外部函数中的变量 闭包中的外部变量
内置作用域 Python预先定义的内置标识符 len, range, print

# 7.2.LEGB原则

Python采用LEGB原则查找变量:

  • L: Local(本地作用域)
  • E: Enclosing(嵌套函数的外部函数作用域)
  • G: Global(全局作用域)
  • B: Built-in(内置作用域)
name = "全局变量"

def outer():
    name = "外部函数变量"
    def inner():
        name = "内部函数变量"
        print(name)  # 输出"内部函数变量"
    inner()
    print(name)      # 输出"外部函数变量"

outer()
print(name)          # 输出"全局变量"
1
2
3
4
5
6
7
8
9
10
11
12

# 7.3.global关键字

global关键字允许我们在函数内部声明某个变量为全局变量,从而可以在函数内部修改它。

counter = 0

def increment():
    global counter
    counter += 1

increment()
increment()
print(counter)  # 2
1
2
3
4
5
6
7
8
9

注意事项

  • 没有global关键字时,在函数内对一个变量赋值会将其作为局部变量处理
  • 使用global后,函数内的变量就直接引用外部全局变量

# 7.4.nonlocal关键字

nonlocal关键字用于在嵌套函数中声明变量来自最近的一层非全局作用域(外层函数)。

def outer():
    x = "local"

    def inner():
        nonlocal x  # 声明 x 来自外层作用域
        x = "nonlocal"
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
# inner: nonlocal
# outer: nonlocal
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 8.高级函数特性

# 8.1.函数作为参数

函数不仅可以像变量一样赋值给其他变量,还可以作为参数传递给其他函数。

def apply_operation(numbers, operation):
    """对数字列表应用操作"""
    return [operation(x) for x in numbers]

def square(x):
    return x ** 2

def double(x):
    return x * 2

numbers = [1, 2, 3, 4, 5]
squared = apply_operation(numbers, square)
doubled = apply_operation(numbers, double)

print(squared)  # [1, 4, 9, 16, 25]
print(doubled)  # [2, 4, 6, 8, 10]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 8.2.嵌套函数

嵌套函数是指在一个函数内部定义另一个函数。内部函数可以访问外部函数的参数和局部变量。

def greet(name):
    def format_message():
        return f"Hello, {name}!"
    return format_message()

print(greet("Alice"))  # Hello, Alice!
1
2
3
4
5
6

用途

  • 实现闭包(closure)
  • 将某些逻辑封装到本地作用域
  • 作为工厂函数创建带记忆的数据

# 8.3.闭包

闭包是指一个函数可以"记住"它被创建时的环境,即使在其外部函数已经执行完毕后,内部函数依然能够访问其外部作用域的变量。

def make_multiplier(factor):
    """创建乘法器函数"""
    def multiplier(x):
        return x * factor
    return multiplier

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))  # 10
print(triple(5))  # 15
1
2
3
4
5
6
7
8
9
10
11

特点

  • 内部函数引用了外部函数的局部变量
  • 外部函数返回内部函数
  • 内部函数可以访问外部函数的变量,即使外部函数已经执行完毕

# 8.4.装饰器

装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器常用于在不修改原函数代码的情况下,动态地为其添加新功能。

def my_decorator(func):
    def wrapper():
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

带参数的装饰器

def logger(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数 {func.__name__},参数:{args} {kwargs}")
        return func(*args, **kwargs)
    return wrapper

@logger
def add(x, y, **kwargs):
    return x + y

print(add(3, 5, a=1, b=2))  # 8
1
2
3
4
5
6
7
8
9
10
11

# 9.匿名函数 (Lambda)

匿名函数(lambda表达式)是一种快速定义简单函数的方法,通常用于一些无需命名、只用一次的小函数场景。

# 9.1.基本语法

lambda 参数1, 参数2, ... : 表达式
1

# 9.2.基本用法

# 基本 lambda 函数
square = lambda x: x ** 2
print(square(5))  # 25

# 在排序中使用
students = [
    {'name': 'Alice', 'grade': 85},
    {'name': 'Bob', 'grade': 92},
    {'name': 'Charlie', 'grade': 78}
]

# 按成绩排序
sorted_students = sorted(students, key=lambda x: x['grade'])
print(sorted_students)

# 在 map 中使用
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)  # [1, 4, 9, 16, 25]

# 在 filter 中使用
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)  # [2, 4]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

特点

  • 只能包含表达式,不能包含语句
  • 自动返回表达式的值
  • 适合简单的函数逻辑

# 10.递归函数

递归函数是函数调用自身来解决问题的方法,适合解决可以被分解为规模更小、相似子问题的任务。

# 10.1.基本结构

def func(params):
    if 终止条件:
        return 结果
    else:
        # 递归调用自身
        return func(更小规模的参数)
1
2
3
4
5
6

# 10.2.递归示例

def factorial(n):
    """计算阶乘的递归函数"""
    if n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n - 1)

print(factorial(5))  # 120

def fibonacci(n):
    """计算斐波那契数列"""
    if n <= 1:
        return n
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

for i in range(10):
    print(fibonacci(i), end=" ")  # 0 1 1 2 3 5 8 13 21 34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

注意事项

  • 必须设置基线条件(终止条件),避免无限递归
  • 递归深度有限制,可能导致栈溢出
  • 对于规模较大的问题效率较低

# 11.错误处理

在函数中进行错误处理可以提升程序的健壮性和用户体验。

# 11.1.基本语法

def 函数名(参数):
    try:
        # 可能抛出异常的操作
    except 异常类型1:
        # 异常类型1的处理代码
    except 异常类型2:
        # 异常类型2的处理代码
    else:
        # 没有发生异常时的代码
    finally:
        # 无论是否发生异常都执行
1
2
3
4
5
6
7
8
9
10
11

# 11.2.实际应用

def safe_divide(a, b):
    """安全的除法函数"""
    try:
        result = a / b
    except ZeroDivisionError:
        return "错误:除数不能为零"
    except TypeError:
        return "错误:参数类型不正确"
    else:
        return result

print(safe_divide(10, 2))   # 5.0
print(safe_divide(10, 0))   # 错误:除数不能为零
print(safe_divide(10, 'a')) # 错误:参数类型不正确
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 12.实用函数示例

# 12.1.数据处理函数

def analyze_numbers(numbers):
    """分析数字列表"""
    if not numbers:
        return None

    analysis = {
        'count': len(numbers),
        'sum': sum(numbers),
        'mean': sum(numbers) / len(numbers),
        'max': max(numbers),
        'min': min(numbers)
    }
    return analysis

data = [10, 20, 30, 40, 50]
result = analyze_numbers(data)
print(result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 12.2.文件处理函数

def read_file_safely(filename):
    """安全读取文件内容"""
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            return file.read()
    except FileNotFoundError:
        return f"错误:文件 {filename} 不存在"
    except Exception as e:
        return f"读取文件时出错:{str(e)}"

def process_csv_data(file_path, delimiter=','):
    """处理CSV数据"""
    import csv
    data = []

    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            reader = csv.reader(file, delimiter=delimiter)
            for row in reader:
                data.append(row)
        return data
    except Exception as e:
        print(f"处理CSV文件时出错:{e}")
        return None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 13.综合示例

# 13.1.学生管理系统

def create_student_management_system():
    """创建学生管理系统"""
    students = []

    def add_student(name, age, grade):
        """添加学生"""
        student = {
            'name': name,
            'age': age,
            'grade': grade
        }
        students.append(student)
        print(f"学生 {name} 添加成功")

    def find_student(name):
        """查找学生"""
        for student in students:
            if student['name'].lower() == name.lower():
                return student
        return None

    def get_student_statistics():
        """获取学生统计信息"""
        if not students:
            return None

        total_students = len(students)
        average_grade = sum(s['grade'] for s in students) / total_students
        best_student = max(students, key=lambda x: x['grade'])

        return {
            'total_students': total_students,
            'average_grade': round(average_grade, 2),
            'best_student': best_student
        }

    def display_all_students():
        """显示所有学生"""
        if not students:
            print("没有学生记录")
            return

        print("\n所有学生信息:")
        for i, student in enumerate(students, 1):
            print(f"{i}. 姓名: {student['name']}, "
                  f"年龄: {student['age']}, 成绩: {student['grade']}")

    return {
        'add_student': add_student,
        'find_student': find_student,
        'get_statistics': get_student_statistics,
        'display_all': display_all_students
    }

# 使用示例
sms = create_student_management_system()
sms['add_student']('Alice', 20, 95)
sms['add_student']('Bob', 21, 87)
sms['display_all']()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# 14.最佳实践

# 14.1.函数设计原则

  1. 单一职责:每个函数只做一件事
  2. 描述性命名:使用有意义的函数名
  3. 保持简短:函数应该简短且专注
  4. 使用文档字符串:为函数添加适当的文档
  5. 避免副作用:函数不应该修改外部状态,除非明确需要

# 14.2.参数设计

  1. 合理使用默认参数:使函数更灵活
  2. 参数顺序:位置参数在前,默认参数在后
  3. 使用*args和kwargs**:提高函数灵活性
  4. 参数验证:在函数开始处验证参数

# 14.3.错误处理

  1. 处理异常:在适当的地方处理可能的错误
  2. 提供有意义的错误信息:帮助用户理解问题
  3. 使用try-except:优雅地处理异常情况

# 14.4.性能考虑

  1. 避免不必要的计算:将重复计算提取到函数外部
  2. 使用生成器:对于大数据集使用生成器函数
  3. 缓存结果:对于昂贵的计算考虑缓存

# 15.总结

函数是Python编程的核心概念,掌握函数的定义、调用、参数传递、返回值、作用域等概念对于编写高质量的Python代码至关重要。通过合理使用函数,我们可以:

  • 提高代码的可重用性和可维护性
  • 实现模块化编程
  • 简化复杂问题的解决
  • 提高代码的可读性和可测试性

掌握函数的高级特性如闭包、装饰器、递归等,能够让我们编写更加灵活和强大的Python程序。