程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Python 基础

    • 环境搭建
    • 标识符
    • 变量
    • 缩进和注释
    • 数据类型
    • 数据类型转换
    • 运算符
    • 字符串
    • 列表
    • 元组
    • 字典
    • 集合
    • if判断
    • for循环
    • while循环
    • 循环综合练习
    • Python函数
      • 1. 什么是函数?为什么使用它?
      • 2. 函数的定义与调用
        • 2.1 定义函数
        • 2.2 调用函数
      • 3. 函数的参数
        • 3.1 位置参数 (Positional Arguments)
        • 3.2 关键字参数 (Keyword Arguments)
        • 3.3 默认参数 (Default Arguments)
        • 3.4 可变位置参数 *args
        • 3.5 可变关键字参数 **kwargs
        • 3.6 参数的顺序
      • 4. 函数的返回值 return
        • 4.1 返回单个值
        • 4.2 返回多个值
        • 4.3 隐式返回 None
      • 5. 函数的文档字符串 (Docstrings)
      • 6. 变量作用域 (Scope):变量的生存空间
        • 6.1 局部变量 (Local Variables)
        • 6.2 全局变量 (Global Variables)
        • 6.3 LEGB 查找规则示例:同名变量的“遮蔽”
        • 6.4 使用 global 关键字修改全局变量
        • 6.5 使用 nonlocal 关键字修改嵌套作用域变量
        • 6.6 作用域的最佳实践
      • 7. 高阶函数 (Higher-Order Functions)
        • 7.1 函数作为参数
        • 7.2 函数作为返回值 (闭包)
      • 8. 匿名函数 lambda
      • 9. 类型提示 (Type Hinting)
    • 函数与循环实战
    • 生成式
    • 文件读写
    • 面向对象
    • 面向对象综合案例
  • Python 进阶

  • Python
  • Python 基础
scholar
2025-07-20
目录

Python函数

# Python函数

在 Python 编程中,函数 (Function) 是组织代码的基本构建块。它是一段封装了特定任务、可重复使用的代码。掌握函数是编写高效、可读、可维护代码的第一步。


# 1. 什么是函数?为什么使用它?

想象一下,你正在写一个程序,需要在三个不同的地方计算圆的面积。如果没有函数,你可能需要写三遍同样的代码:

# 第一次
pi = 3.14159
radius1 = 5
area1 = pi * (radius1 ** 2)
print(area1)

# 第二次
radius2 = 10
area2 = pi * (radius2 ** 2)
print(area2)

# 第三次
radius3 = 3
area3 = pi * (radius3 ** 2)
print(area3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

这种重复不仅繁琐,而且如果计算公式需要修改(比如提高 pi 的精度),你就得修改所有地方。

函数解决了这个问题。我们可以将计算面积的逻辑封装起来:

def calculate_circle_area(radius):
    """计算并返回圆的面积。"""
    pi = 3.14159
    return pi * (radius ** 2)

# 现在,只需调用函数即可
print(calculate_circle_area(5))
print(calculate_circle_area(10))
print(calculate_circle_area(3))
1
2
3
4
5
6
7
8
9

使用函数的核心优势:

  • 提高代码复用性 (Reusability):一次定义,多次调用。
  • 增强代码可读性 (Readability):函数名(如 calculate_circle_area)清晰地表达了代码块的功能。
  • 简化代码维护 (Maintainability):只需修改函数内部的逻辑,所有调用处都会自动更新。
  • 实现代码模块化 (Modularity):将复杂的程序分解为一个个简单的小任务。

# 2. 函数的定义与调用

# 2.1 定义函数

使用 def 关键字来定义一个函数。

  • 基本语法:
    def function_name(parameter1, parameter2, ...):
        """
        这里是函数的文档字符串 (docstring),可选,但强烈推荐。
        它解释了函数的功能、参数和返回值。
        """
        # 函数体 (Function Body)
        # 执行特定任务的代码
        return result # 使用 return 语句返回结果,可选
    
    1
    2
    3
    4
    5
    6
    7
    8
  • 函数命名规范:通常使用蛇形命名法 (snake_case),即全小写字母,单词间用下划线分隔,例如 calculate_sum。

# 2.2 调用函数

定义函数后,通过 函数名() 的形式来执行(调用)它。

  • 示例:
    # 定义一个打招呼的函数
    def greet(name):
        """向指定的人打印问候信息。"""
        print(f"Hello, {name}! 欢迎来到 Python 的世界。")
    
    # 调用函数
    greet("Alice")
    greet("Bob")
    
    # 输出:
    # Hello, Alice! 欢迎来到 Python 的世界。
    # Hello, Bob! 欢迎来到 Python 的世界。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

# 3. 函数的参数

参数是函数与外部世界沟通的桥梁。调用函数时传入的值称为实参 (Argument),函数定义中的变量称为形参 (Parameter)。

# 3.1 位置参数 (Positional Arguments)

调用时,实参的值按位置顺序依次传递给形参。这是最基本的参数类型。

def describe_pet(animal_type, pet_name):
    """显示宠物的信息。"""
    print(f"我有一只 {animal_type}。")
    print(f"它的名字叫 {pet_name}。")

describe_pet("仓鼠", "皮蛋")
# 输出:
# 我有一只 仓鼠。
# 它的名字叫 皮蛋。
1
2
3
4
5
6
7
8
9

"仓鼠" 对应 animal_type,"皮蛋" 对应 pet_name。顺序不能错。

# 3.2 关键字参数 (Keyword Arguments)

调用时,通过 形参名=值 的形式指定实参。这允许我们不按顺序传递参数,并使代码更清晰。

describe_pet(pet_name="团子", animal_type="猫")
# 输出:
# 我有一只 猫。
# 它的名字叫 团子。
1
2
3
4

# 3.3 默认参数 (Default Arguments)

定义函数时,可以为形参提供一个默认值。如果在调用时没有为该参数提供实参,它将使用默认值。

def greet_user(username, greeting="你好"):
    """向用户打招呼,可自定义问候语。"""
    print(f"{greeting}, {username}!")

greet_user("张三")         # 使用默认问候语
greet_user("李四", "早上好") # 提供新的问候语,覆盖默认值

# 输出:
# 你好, 张三!
# 早上好, 李四!
1
2
3
4
5
6
7
8
9
10

重要陷阱:应避免使用可变对象(如列表 [] 或字典 {})作为默认参数。因为默认参数在函数定义时只被创建一次,后续调用会共享这同一个对象。

# 3.4 可变位置参数 *args

当不确定函数会接收多少个位置参数时,可以使用 *args。它会将所有多余的位置参数收集到一个元组 (tuple) 中。

def calculate_sum(*args):
    """计算所有输入数字的和。"""
    print(f"接收到的参数 (元组): {args}")
    total = 0
    for num in args:
        total += num
    return total

print(calculate_sum(1, 2, 3))
print(calculate_sum(10, 20, 30, 40, 50))

# 输出:
# 接收到的参数 (元组): (1, 2, 3)
# 9
# 接收到的参数 (元组): (10, 20, 30, 40, 50)
# 150
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3.5 可变关键字参数 **kwargs

当不确定会接收多少个关键字参数时,使用 **kwargs。它会将所有未定义的关键字参数收集到一个字典 (dict) 中。

def build_profile(first, last, **kwargs):
    """创建一个字典,包含我们知道的关于用户的一切。"""
    profile = {'first_name': first, 'last_name': last}
    print(f"接收到的关键字参数 (字典): {kwargs}")
    profile.update(kwargs) # 将 kwargs 字典内容更新到 profile
    return profile

user_profile = build_profile("爱因", "斯坦", location="普林斯顿", field="物理")
print(user_profile)

# 输出:
# 接收到的关键字参数 (字典): {'location': '普林斯顿', 'field': '物理'}
# {'first_name': '爱因', 'last_name': '斯坦', 'location': '普林斯顿', 'field': '物理'}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.6 参数的顺序

当组合使用所有参数类型时,必须遵循以下顺序:

  1. 标准位置参数
  2. *args
  3. 关键字参数或默认参数
  4. **kwargs

# 4. 函数的返回值 return

return 语句用于从函数中退出,并返回一个值。

# 4.1 返回单个值

def square(number):
    return number * number

result = square(4)
print(result) # 输出: 16
1
2
3
4
5

# 4.2 返回多个值

Python 函数可以一次返回多个值,它们会被打包成一个元组。

def divide_with_remainder(a, b):
    """返回商和余数。"""
    quotient = a // b
    remainder = a % b
    return quotient, remainder # 返回多个值

q, r = divide_with_remainder(10, 3)
print(f"商: {q}, 余数: {r}") # 输出: 商: 3, 余数: 1

result_tuple = divide_with_remainder(10, 3)
print(result_tuple) # 输出: (3, 1)
1
2
3
4
5
6
7
8
9
10
11

# 4.3 隐式返回 None

如果一个函数没有 return 语句,或者 return 后面没有跟任何值,它会自动返回 None。

def say_hello(name):
    print(f"你好, {name}")

result = say_hello("世界")
print(result)
# 输出:
# 你好, 世界
# None
1
2
3
4
5
6
7
8

# 5. 函数的文档字符串 (Docstrings)

文档字符串是解释函数用途的三引号字符串。它是函数定义中的第一条语句。良好的文档是高质量代码的标志。

def power(base, exponent):
    """
    计算并返回一个数的幂。

    Args:
        base (int or float): 基数。
        exponent (int or float): 指数。

    Returns:
        int or float: base 的 exponent 次幂的结果。
    """
    return base ** exponent

# 查看文档字符串的两种方式
print(help(power))
print(power.__doc__)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 6. 变量作用域 (Scope):变量的生存空间

作用域是编程中一个至关重要的概念,它定义了一个变量能够被访问的区域或上下文。理解作用域有助于避免命名冲突和难以追踪的 Bug。

Python 的变量作用域遵循 LEGB 规则的查找顺序,即当代码引用一个变量时,Python 会按以下顺序搜索该变量:

  1. L (Local):局部作用域。这是最内层的范围,包含在当前函数内部定义的任何变量。
  2. E (Enclosing):嵌套作用域。如果一个函数嵌套在另一个函数中,这个作用域包含外部函数中定义的变量。
  3. G (Global):全局作用域。在 Python 文件的顶层(所有函数之外)定义的变量。
  4. B (Built-in):内置作用域。Python 预先定义的名称,如 print(), len(), str 等,在任何地方都可直接使用。

# 6.1 局部变量 (Local Variables)

局部变量是在函数内部定义的变量,它的生命周期与函数共存。

  • 生命周期:当函数被调用时,局部变量被创建;当函数执行完毕并返回时,局部变量被销毁。
  • 作用范围:只能在定义它的函数内部被访问。函数的参数也属于局部变量。
def show_local_scope():
    # 下面三个都是局部变量
    animal = "金毛" 
    name = "旺财"
    age = 3
    print(f"函数内部: {name}是一只{age}岁的{animal}。")

show_local_scope()
# 输出:
# 函数内部: 旺财是一只3岁的金毛。

# 在函数外部尝试访问局部变量会导致错误
# print(animal) # 会引发 NameError: name 'animal' is not defined
1
2
3
4
5
6
7
8
9
10
11
12
13

# 6.2 全局变量 (Global Variables)

全局变量是在模块的顶层定义的变量,可以在文件的任何地方(包括所有函数内部和外部)被访问。

PI = 3.14159  # 这是一个全局变量
app_version = "1.0.2" # 这也是一个全局变量

def calculate_circle_circumference(radius):
    # 函数内部可以自由地“读取”全局变量的值
    return 2 * PI * radius

print(f"圆周率是: {PI}")
print(f"半径为5的圆周长是: {calculate_circle_circumference(5)}")
print(f"当前应用版本: {app_version}")

# 输出:
# 圆周率是: 3.14159
# 半径为5的圆周长是: 31.4159
# 当前应用版本: 1.0.2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 6.3 LEGB 查找规则示例:同名变量的“遮蔽”

当不同作用域中存在同名变量时,Python 会根据 LEGB 规则使用它找到的第一个变量。这通常意味着局部变量会“遮蔽” (shadow) 全局变量。

x = "我是全局的 x"

def my_func():
    x = "我是局部的 x" # 这个局部变量“遮蔽”了全局的 x
    print(f"在函数内部,x 是: {x}")

my_func()
print(f"在函数外部,x 依然是: {x}")

# 输出:
# 在函数内部,x 是: 我是局部的 x
# 在函数外部,x 依然是: 我是全局的 x
1
2
3
4
5
6
7
8
9
10
11
12

在 my_func 内部,Python 在局部作用域 (L) 就找到了 x,因此不会再继续向外(全局 G)查找。

# 6.4 使用 global 关键字修改全局变量

默认情况下,在函数内部对一个变量进行赋值操作 (=, += 等) 会创建一个新的局部变量。如果你的意图是修改全局变量,就必须使用 global 关键字明确告诉 Python。

  • 错误示范(未修改全局变量)

    player_score = 100
    
    def failed_increase_score(points):
        # 下面这行代码没有使用 global,
        # 因此 Python 会创建一个新的、名为 player_score 的“局部变量”。
        player_score = points 
        print(f"函数内部的 '局部' player_score: {player_score}")
    
    failed_increase_score(150)
    print(f"函数外部的 '全局' player_score 并未改变: {player_score}")
    
    # 输出:
    # 函数内部的 '局部' player_score: 150
    # 函数外部的 '全局' player_score 并未改变: 100
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • 正确示范

    player_score = 100
    
    def increase_score(points):
        global player_score # 明确声明:我要操作的是全局作用域的 player_score
        player_score += points
        print(f"分数增加 {points}!当前分数: {player_score}")
    
    increase_score(20)
    print(f"最终分数: {player_score}")
    
    # 输出:
    # 分数增加 20!当前分数: 120
    # 最终分数: 120
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

# 6.5 使用 nonlocal 关键字修改嵌套作用域变量

nonlocal 关键字用于在嵌套函数中,修改外部(但非全局)函数中的变量。

def outer_func():
    x = "我是外部变量" # 嵌套作用域 (E)
    def inner_func():
        nonlocal x # 声明 x 不是局部变量,而是来自外部嵌套作用域 (Enclosing)
        x = "我在内部函数中被修改了"
        print(f"内部调用: {x}")
    
    inner_func()
    print(f"外部调用: {x}")

outer_func()
# 输出:
# 内部调用: 我在内部函数中被修改了
# 外部调用: 我在内部函数中被修改了
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 6.6 作用域的最佳实践

  • 尽量避免滥用全局变量:全局变量使得代码状态难以追踪,因为任何函数都可能在任何时候修改它。这会增加调试难度并降低代码的可维护性。
  • 优先使用参数和返回值:在函数间传递数据的最佳方式是通过函数参数和 return 语句,这使得数据流向清晰可见。
  • 仅在必要时使用 global 和 nonlocal:当你需要管理一个跨多个函数调用的共享状态(如配置、缓存、计数器)时,global 是必要的。但使用前请三思是否有更好的设计模式。
  • 常量使用大写:对于不希望在程序中被修改的全局变量(即常量),通常使用全大写字母加下划线的命名方式,如 MAX_CONNECTIONS = 10。这是一种约定,提醒开发者不要修改它。

# 7. 高阶函数 (Higher-Order Functions)

在 Python 中,函数是“一等公民”,这意味着它们可以像任何其他对象(如整数、字符串)一样被处理:

  • 可以被赋值给变量。
  • 可以作为参数传递给其他函数。
  • 可以作为其他函数的返回值。

接收函数作为参数或返回一个函数的函数,被称为高阶函数。

# 7.1 函数作为参数

def square(n):
    return n * n

def cube(n):
    return n * n * n

def apply_function(func, value):
    """接收一个函数和值,将函数应用于该值。"""
    return func(value)

result_sq = apply_function(square, 5) # 将 square 函数传递进去
result_cu = apply_function(cube, 5)

print(result_sq) # 输出: 25
print(result_cu) # 输出: 125
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 7.2 函数作为返回值 (闭包)

一个返回函数的函数。返回的那个内部函数记住了其定义时所在的环境(作用域),这被称为闭包 (Closure)。

def create_multiplier(n):
    """创建一个乘以 n 的函数。"""
    def multiplier(x):
        return x * n # 这里的 n 来自外部函数的环境
    return multiplier

# 创建一个“乘以3”的函数
times3 = create_multiplier(3)
# 创建一个“乘以5”的函数
times5 = create_multiplier(5)

print(times3(10)) # 输出: 30
print(times5(10)) # 输出: 50
1
2
3
4
5
6
7
8
9
10
11
12
13

# 8. 匿名函数 lambda

lambda 关键字用于创建小型的、没有名字的匿名函数。它特别适用于需要一个简单函数作为参数的场景。

  • 语法: lambda arguments: expression
  • 特点: 只能包含一个表达式,该表达式的结果就是返回值。
# 普通函数
def add(x, y):
    return x + y

# 等价的 lambda 函数
add_lambda = lambda x, y: x + y

print(add(2, 3))       # 输出: 5
print(add_lambda(2, 3)) # 输出: 5
1
2
3
4
5
6
7
8
9

lambda 的常见用途: 与 map(), filter(), sorted() 等内置函数结合使用。

numbers = [1, 2, 3, 4, 5]

# 使用 map() 将列表中每个元素平方
squares = list(map(lambda x: x**2, numbers))
print(squares) # 输出: [1, 4, 9, 16, 25]

# 使用 filter() 筛选出列表中的偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # 输出: [2, 4]
1
2
3
4
5
6
7
8
9

# 9. 类型提示 (Type Hinting)

从 Python 3.5 开始,可以为函数参数和返回值添加类型提示。类型提示不影响程序的运行,但能极大地增强代码的可读性,并帮助静态代码分析工具(如 MyPy)和 IDE(如 VS Code, PyCharm)发现潜在的错误。

def greet(name: str) -> str:
    """
    接收一个字符串,返回一个带问候语的字符串。
    :param name: 用户的名字 (字符串)
    :return: 问候语 (字符串)
    """
    return f"Hello, {name}"

greeting_message = greet("Guido")
print(greeting_message) # 输出: Hello, Guido
1
2
3
4
5
6
7
8
9
10
  • name: str 表示 name 参数期望是一个字符串。
  • -> str 表示该函数期望返回一个字符串。
编辑此页 (opens new window)
上次更新: 2025/07/23, 06:33:16
循环综合练习
函数与循环实战

← 循环综合练习 函数与循环实战→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式