在 Python 中,函数是代码复用的核心载体,也是实现模块化编程的基础。无论是简单的打印输出,还是复杂的业务逻辑,函数都能将代码封装成可复用的单元。今天这篇文章,我们就来系统梳理 Python 函数的核心知识,从基础概念到进阶用法,帮你彻底搞懂函数。
一、函数的基本概念:什么是函数?
函数是封装了特定逻辑的代码块,它接收输入(可选)、执行操作、返回结果(可选)。简单来说,函数就像一个 “工具”:你给它一些材料(参数),它帮你完成特定任务(逻辑),最后可能还给你一个成品(返回值)。
函数的核心价值在于:
- 代码复用:一次定义,多次调用,避免重复编写相同逻辑
- 模块化:将复杂问题拆解为多个函数,每个函数负责单一职责
- 可维护性:修改函数内部逻辑,不影响调用它的代码
1.1 形参与实参:函数与数据的 “接口”
函数在定义和调用时,涉及两个关键概念:
-
形参(形式参数):定义函数时声明的参数,是函数接收数据的 “占位符”,用变量名表示。
例:def add(a, b):中的a和b就是形参。 -
实参(实际参数):调用函数时传入的数据,是形参的 “具体值”。
例:add(1, 2)中的1和2就是实参。
形参和实参的关系:调用函数时,实参会赋值给对应的形参,函数内部通过形参使用这些数据。
二、函数的参数:灵活传递数据的多种方式
Python 函数的参数设计非常灵活,支持多种类型的参数,满足不同场景的需求。
2.1 位置参数:按顺序传递的 “必传参数”
位置参数是最基础的参数类型,必须按定义顺序传递,且不能省略。
python
def get_user_info(name, age, gender):
print(f"姓名:{name},年龄:{age},性别:{gender}")
# 必须按 name→age→gender 的顺序传参
get_user_info("张三", 18, "男") # 正确:按顺序传递
get_user_info(18, "张三", "男") # 错误:顺序错误导致数据含义混淆
位置参数的核心是 “顺序”,调用时参数的位置必须与定义时一致。
2.2 默认参数:可传可不传的 “便捷参数”
如果给位置参数设置默认值,它就变成了默认参数。默认参数在调用时可以省略(使用默认值),但必须定义在位置参数之后。
python
# 定义:默认参数 gender 放在位置参数 name、age 之后
def get_user_info(name, age, gender="未知"):
print(f"姓名:{name},年龄:{age},性别:{gender}")
# 调用时可省略默认参数
get_user_info("张三", 18) # 输出:姓名:张三,年龄:18,性别:未知
get_user_info("李四", 20, "女") # 输出:姓名:李四,年龄:20,性别:女
注意:默认参数的默认值是 “定义时计算” 的,而非调用时。如果默认值是可变对象(如列表),可能会出现意外结果,建议默认值用不可变对象(如 None、字符串)。
2.3 关键字参数:不依赖顺序的 “明确传递”
调用函数时,通过 “参数名 = 值” 的形式传递数据,称为关键字参数。它的优势是不需要遵守位置顺序,让代码更易读。
python
def get_user_info(name, age, gender):
print(f"姓名:{name},年龄:{age},性别:{gender}")
# 关键字参数调用,顺序可以打乱
get_user_info(age=18, name="张三", gender="男") # 正确
关键字参数可以和位置参数混合使用,但位置参数必须放在关键字参数之前:
python
get_user_info("张三", gender="男", age=18) # 正确:位置参数在前
get_user_info(gender="男", "张三", age=18) # 错误:位置参数不能在关键字参数后
2.4 强制关键字参数:必须用关键字传递的参数
在定义函数时,用 * 作为分隔符,* 后面的参数就是强制关键字参数—— 调用时必须用关键字传递,否则会报错。
python
def get_user_info(name, *, age, gender): # * 后面的 age、gender 是强制关键字参数
print(f"姓名:{name},年龄:{age},性别:{gender}")
get_user_info("张三", age=18, gender="男") # 正确:用关键字传递
get_user_info("张三", 18, "男") # 错误:age、gender 未用关键字传递
强制关键字参数的作用是避免参数顺序混淆,尤其适合参数较多的函数。
2.5 不定项参数:接收任意数量的参数
当不确定需要传递多少个参数时,可用不定项参数,分为两种:
2.5.1 不定项位置参数 *args
*args 用于接收0~n 个位置参数,传递后会被打包成一个元组(tuple)。
python
def sum_numbers(*args):
print("接收的参数:", args) # args 是元组
return sum(args)
print(sum_numbers(1, 2, 3)) # 输出:6(args=(1,2,3))
print(sum_numbers()) # 输出:0(args=())
*args 中的 args 是约定俗成的名称,也可以用其他名字(如 *nums),但建议遵循惯例。
2.5.2 不定项关键字参数 **kwargs
**kwargs 用于接收0~n 个关键字参数,传递后会被打包成一个字典(dict)。
python
def print_info(** kwargs):
print("接收的参数:", kwargs) # kwargs 是字典
for key, value in kwargs.items():
print(f"{key}:{value}")
print_info(name="张三", age=18, gender="男")
# 输出:
# 接收的参数: {'name': '张三', 'age': 18, 'gender': '男'}
# name:张三
# age:18
# gender:男
同样,kwargs 是约定俗成的名称,可自定义(如 **info)。
2.5.3 不定项参数的组合使用
参数定义的完整顺序(从左到右)是:
** 位置参数 → 默认参数 → *args → 强制关键字参数 → kwargs
python
def func(a, b=10, *args, c, **kwargs):
print(f"a={a}, b={b}, args={args}, c={c}, kwargs={kwargs}")
func(1, 2, 3, 4, c=5, d=6, e=7)
# 输出:a=1, b=2, args=(3,4), c=5, kwargs={'d':6, 'e':7}
三、匿名函数:简洁的 “一次性” 函数
匿名函数是没有名字的函数,用 lambda 关键字定义,适合编写简单的、只使用一次的逻辑。
3.1 匿名函数的语法
python
lambda [参数列表] : 函数体
特点:
- 函数体只有 1 行代码,不能写多行
- 若需返回数据,省略
return(函数体会自动返回结果) - 没有函数名,通常作为 “临时工具” 使用
3.2 匿名函数 vs 普通函数
| 类型 | 定义方式 | 复用性 | 适用场景 |
|---|---|---|---|
| 普通函数 | def 函数名(): | 高 | 复杂逻辑、需要多次调用 |
| 匿名函数 | lambda | 低 | 简单逻辑、临时使用(如参数) |
3.3 匿名函数的使用场景
最常见的是作为高阶函数(如 sorted、map、filter)的参数:
python
# 1. 作为 sorted 的排序依据
students = [("张三", 18), ("李四", 16), ("王五", 20)]
# 按年龄排序(用 lambda 提取年龄作为key)
sorted_students = sorted(students, key=lambda x: x[1])
print(sorted_students) # 输出:[('李四', 16), ('张三', 18), ('王五', 20)]
# 2. 作为 map 的映射逻辑
numbers = [1, 2, 3, 4]
# 计算每个数的平方
squares = list(map(lambda x: x**2, numbers))
print(squares) # 输出:[1, 4, 9, 16]
四、函数的分类:按参数和返回值划分
根据函数是否有参数、是否有返回值,可分为 5 类,覆盖所有函数场景:
4.1 任务型函数:无参数,无返回值
只执行操作,不接收数据,也不返回结果。
python
def print_welcome():
print("欢迎使用本系统!") # 只做一件事:打印欢迎语
4.2 生产型函数:无参数,有返回值
不接收数据,但会生成并返回结果(像 “生产者”)。
python
import random
def get_random_num():
return random.randint(1, 100) # 无参数,但返回随机数
4.3 消费型函数:有参数,无返回值
接收数据并处理,但不返回结果(像 “消费者”)。
python
def print_user_name(name):
print(f"用户名:{name}") # 接收name,打印后不返回
4.4 功能型函数:有参数,有返回值
接收数据,处理后返回结果(最常用的类型)。
python
def add(a, b):
return a + b # 接收a和b,返回和
4.5 断言型函数:返回布尔值的功能型函数
专门用于判断条件,返回 True 或 False,通常作为逻辑判断的依据。
python
def is_adult(age):
return age >= 18 # 判断是否成年,返回bool
if is_adult(19):
print("已成年")
五、函数是对象:更灵活的用法
在 Python 中,万物皆对象,函数也不例外。这意味着函数可以:
5.1 赋值给变量
python
def greet():
print("Hello")
func_var = greet # 函数赋值给变量
func_var() # 调用变量(等价于调用greet()),输出:Hello
5.2 作为函数的参数
python
def add(a, b):
return a + b
def multiply(a, b):
return a * b
# 高阶函数:接收函数作为参数
def calculate(func, x, y):
return func(x, y)
print(calculate(add, 2, 3)) # 输出:5(调用add(2,3))
print(calculate(multiply, 2, 3)) # 输出:6(调用multiply(2,3))
5.3 作为函数的返回值
python
def get_operation(operator):
if operator == "+":
return lambda a, b: a + b # 返回匿名函数
elif operator == "*":
return lambda a, b: a * b
add_func = get_operation("+")
print(add_func(2, 3)) # 输出:5
六、补充:函数的进阶知识
6.1 函数的返回值细节
- 函数可以返回任意类型的数据(整数、列表、字典、甚至函数)
- 若函数没有
return,默认返回None - 用
return可以提前终止函数(执行到return后,后续代码不执行) - 可以返回多个值,实际会被打包成元组:
python
def get_name_and_age():
return "张三", 18 # 等价于 return ("张三", 18)
name, age = get_name_and_age() # 解包赋值
print(name, age) # 输出:张三 18
6.2 函数的嵌套
函数内部可以定义另一个函数(嵌套函数),内部函数可以访问外部函数的变量。
python
def outer():
x = 10
def inner():
print(x + 5) # 访问外部函数的x
inner() # 调用内部函数
outer() # 输出:15
6.3 函数的作用域
变量的可见范围,分为:
- 局部作用域:函数内部定义的变量,仅在函数内有效
- 全局作用域:函数外部定义的变量,整个模块有效
- 嵌套作用域:嵌套函数中,外层函数的变量对内部函数可见
用 global 声明使用全局变量,nonlocal 声明使用嵌套作用域的变量:
python
x = 100 # 全局变量
def func():
global x # 声明使用全局x
x = 200
func()
print(x) # 输出:200(全局x被修改)
6.4 装饰器:增强函数功能的 “包装器”
装饰器是一种特殊的函数,用于在不修改原函数代码的前提下,增强函数功能(如计时、日志、权限校验)。
python
# 定义一个计时装饰器
def timer(func):
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs) # 调用原函数
end = time.time()
print(f"函数耗时:{end - start}秒")
return result
return wrapper
# 用 @ 语法使用装饰器
@timer
def slow_func():
time.sleep(1) # 模拟耗时操作
slow_func() # 输出:函数耗时:1.00xxx秒
七、总结
函数是 Python 编程的核心,从基础的参数传递到进阶的装饰器,掌握函数的用法能让你的代码更简洁、高效、可维护。


被折叠的 条评论
为什么被折叠?



