大家好,函数是 Python 编程中最核心的组织代码的方式。无论是简单的数据处理,还是复杂的项目架构,都离不开函数的支撑。这篇文章将从基础概念开始,逐步深入到装饰器等进阶用法,系统性地讲解函数的方方面面。
一、函数基础
1.1 什么是函数
函数是组织好的、可重复使用的代码块,用于完成特定的功能。使用函数可以提高代码的复用性、可读性和可维护性。
函数的核心思想是封装:将一段独立的功能代码封装起来,通过函数名调用,而不需要关心其内部实现细节。
# 没有使用函数:重复代码
print("Hello, 张三")
print("Hello, 李四")
print("Hello, 王五")
# 使用函数:封装重复逻辑
def greet(name):
print(f"Hello, {name}")
greet("张三")
greet("李四")
greet("王五")
1.2 函数的定义与调用
定义函数使用 def 关键字,后跟函数名、括号和冒号:
# 基本语法
def 函数名(参数列表):
"""文档字符串(可选)"""
函数体
return 返回值(可选)
调用函数通过函数名加括号的方式:
# 定义函数
def say_hello():
print("Hello, World!")
# 调用函数
say_hello() # Hello, World!
带参数的函数:
# 定义带参数的函数
def greet(name, age):
print(f"{name} 今年 {age} 岁")
# 调用时传入参数
greet("张三", 25) # 张三 今年 25 岁
1.3 函数的返回值
使用 return 语句返回函数的结果。当函数执行到 return 时,会立即结束并返回指定值。
# 返回单个值
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 8
# 返回多个值(实际上返回一个元组)
def get_user_info():
name = "张三"
age = 25
city = "北京"
return name, age, city
info = get_user_info()
print(info) # ('张三', 25, '北京')
print(info[0]) # 张三
没有 return 的函数:
def just_print():
print("这个函数没有返回值")
result = just_print() # 这个函数没有返回值
print(result) # None
return 的几种情况:
| return | None | 直接结束函数 |
| return 值 | 具体的值 | 返回单个值 |
| return 值1, 值2 | (值1, 值2) | 返回元组 |
二、函数参数
2.1 位置参数
位置参数是最基本的参数类型。调用函数时,必须按定义时的顺序传入参数,且数量必须一致。
def info(name, age, city):
print(f"{name}, {age}岁, 来自{city}")
# 按顺序传入,必须一一对应
info("张三", 25, "北京") # 张三, 25岁, 来自北京
# 参数数量不一致会报错
# info("张三", 25) # TypeError: missing 1 required positional argument
2.2 默认参数
在定义函数时为参数指定默认值。调用时如果不传入该参数,则使用默认值。
注意事项:
默认参数必须放在位置参数之后
默认参数的值在函数定义时确定,不可变类型推荐使用
def greet(name, msg="你好"):
print(f"{msg}, {name}!")
greet("张三") # 你好, 张三!
greet("李四", "欢迎") # 欢迎, 李四!
2.3 关键字参数
调用函数时,通过 参数名=值 的方式传入参数,顺序可以打乱。
def info(name, age, city):
print(f"{name}, {age}岁, 来自{city}")
# 关键字参数调用,顺序可乱
info(city="深圳", age=28, name="王五") # 王五, 28岁, 来自深圳
# 混合使用:位置参数必须在前
info("赵六", city="广州", age=30) # 赵六, 30岁, 来自广州
2.4 可变参数
*args:接收任意数量的位置参数
*args 将传入的多个位置参数打包成一个元组。
def sum_all(*args):
total = 0
for num in args:
total += num
return total
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all()) # 0 可以传0个参数
**kwargs:接收任意数量的关键字参数
**kwargs 将传入的多个关键字参数打包成一个字典。
def show_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
show_info(name="张三", age=25, city="北京")
# 输出:
# name: 张三
# age: 25
# city: 北京
参数组合顺序:
def func(a, b, c=10, *args, **kwargs):
print(f"a={a}, b={b}, c={c}")
print(f"args={args}")
print(f"kwargs={kwargs}")
func(1, 2, 3, 4, 5, name="张三", age=25)
# 输出:
# a=1, b=2, c=3
# args=(4, 5)
# kwargs={'name': '张三', 'age': 25}
2.5 参数解包
列表/元组解包(*):将序列中的元素作为位置参数传入。
def add(a, b, c):
return a + b + c
# 列表解包
numbers = [1, 2, 3]
result = add(*numbers)
print(result) # 6
# 元组解包
values = (4, 5, 6)
result = add(*values)
print(result) # 15
字典解包(**):将字典中的键值对作为关键字参数传入。
def info(name, age, city):
print(f"{name}, {age}岁, 来自{city}")
# 字典解包
data = {"name": "张三", "age": 25, "city": "北京"}
info(**data) # 张三, 25岁, 来自北京
三、变量作用域
3.1 局部变量与全局变量
局部变量:在函数内部定义的变量,只能在函数内部访问。
def func():
x = 10 # 局部变量
print(x) # 可以访问
func() # 10
# print(x) # NameError: name 'x' is not defined
全局变量:在函数外部定义的变量,在整个模块中都可访问。
x = 10 # 全局变量
def func():
print(x) # 可以访问
func() # 10
print(x) # 10
3.2 global 与 nonlocal 关键字
global:在函数内部修改全局变量
count = 0 # 全局变量
def increment():
global count # 声明使用全局变量
count += 1
print(count) # 0
increment()
print(count) # 1
nonlocal:在嵌套函数中修改外层函数的变量
def outer():
x = 10 # 外层函数的变量
def inner():
nonlocal x # 声明修改外层变量
x += 5
print(x) # 10
inner()
print(x) # 15
outer()
四、特殊函数类型
4.1 匿名函数(lambda)
匿名函数使用 lambda 关键字定义,没有函数名,适合编写简单的单行表达式。
语法:
lambda 参数列表: 表达式
# 等价于
def 函数名(参数列表):
return 表达式
基本使用:
# lambda 表达式
add_lambda = lambda a, b: a + b
print(add_lambda(3, 5)) # 8
4.2 高阶函数
高阶函数是接收函数作为参数或返回函数的函数。
map()
对可迭代对象中的每个元素应用函数,返回迭代器。
# 配合 lambda
nums = [1, 2, 3, 4, 5]
result = map(lambda x: x * 2, nums)
print(list(result)) # [2, 4, 6, 8, 10]
filter()
过滤可迭代对象中满足条件的元素,返回迭代器。
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 筛选偶数
evens = filter(lambda x: x % 2 == 0, nums)
print(list(evens)) # [2, 4, 6, 8, 10]
reduce()
对可迭代对象进行累积归约,返回单个值。位于 functools 模块。
from functools import reduce
nums = [1, 2, 3, 4, 5]
# 求和
result = reduce(lambda x, y: x + y, nums)
print(result) # 15
# 带初始值
result = reduce(lambda x, y: x + y, nums, 10)
print(result) # 25
4.3 递归函数
递归是函数调用自身的编程方式,适合解决可分解为相同子问题的问题。
必须包含:
-
终止条件:停止递归的条件
-
递归条件:函数调用自身
# 斐波那契数列
def fibonacci(n):
if n <= 1:
return n
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
递归的注意事项:
import sys
# 默认递归深度限制为 1000
print(sys.getrecursionlimit()) # 1000
五、闭包与装饰器
5.1 闭包
闭包是指在一个函数内部定义了另一个函数,并且内部函数引用了外部函数的变量,而外部函数将其返回。
闭包的条件:
存在函数的嵌套定义
内部函数引用了外部函数的变量
外部函数返回内部函数
def outer(x):
y = 10 # 外部函数的变量
def inner(): # 内部函数
print(x + y) # 引用了外部变量
return inner # 返回内部函数
# 创建闭包
closure = outer(5)
closure() # 15 闭包记住了 x=5 和 y=10
5.2 装饰器
装饰器是一种特殊的闭包,用于在不修改原函数代码的情况下,为函数添加额外功能。
基本语法
# 定义装饰器
def decorator(func):
def wrapper(*args, **kwargs):
# 在函数执行前添加功能
print("函数执行前")
result = func(*args, **kwargs)
# 在函数执行后添加功能
print("函数执行后")
return result
return wrapper
# 使用装饰器
@decorator
def say_hello():
print("Hello!")
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
带参数的装饰器
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("张三")
# 输出三次 Hello, 张三!
六、总结
| 函数基础 | def 定义,return 返回值,文档字符串 |
| 位置参数 | 按顺序传入,数量一致 |
| 默认参数 | 定义时赋值,必须在位置参数之后 |
| 关键字参数 | 通过 参数名=值 传入,顺序可乱 |
| *args | 接收任意数量位置参数,打包为元组 |
| **kwargs | 接收任意数量关键字参数,打包为字典 |
| 参数解包 | * 解包序列,** 解包字典 |
| 全局变量 | 在函数外定义,用 global 修改 |
| 局部变量 | 在函数内定义,外部不可访问 |
| nonlocal | 在嵌套函数中修改外层函数的变量 |
| lambda | 匿名函数,适合简单单行表达式 |
| 高阶函数 | map()、filter()、reduce()、sorted() |
| 递归 | 函数调用自身,需设置基线条件 |
| 闭包 | 嵌套函数引用外部变量,返回内部函数 |
| 装饰器 | 不修改原函数代码,为其添加额外功能 |
函数是 Python 编程的核心组织方式,从基础的定义调用到高级的装饰器,每一个知识点都有其实际应用场景。建议多写多练,在实践中逐步加深理解。
如果觉得这篇内容对你有帮助,欢迎收藏备用。



