在 Python 中,函数(Function)是封装特定逻辑的可重用代码块,用于实现单一、独立的功能。通过函数,我们可以将复杂代码分解为模块化的片段,提高代码的可读性、复用性和可维护性。本文将从基础到高级,详细介绍 Python 函数的核心特性和使用方法。
一、函数的基本定义与调用
1. 函数的定义
使用 def 关键字定义函数,语法格式如下:
def 函数名(参数列表):
"""函数文档字符串(可选,用于说明函数功能)"""
函数体(实现功能的代码)
return 返回值(可选)
- 函数名:遵循标识符规则(字母、数字、下划线,不能以数字开头),建议使用小写字母 + 下划线(snake_case)命名,如
calculate_area。 - 参数列表:函数接收的输入(可选,无参数时留空)。
- 文档字符串(docstring):用三引号包裹的说明文本,可通过
help(函数名)查看,提升代码可读性。 - 函数体:实现具体功能的代码块(需缩进)。
- return 语句:指定函数的返回值(可选,无 return 时默认返回
None)。
2. 函数的调用
定义函数后,通过 函数名(参数) 调用,示例:
# 定义一个计算矩形面积的函数
def calculate_rect_area(length, width):
"""计算矩形面积
参数:
length: 矩形的长
width: 矩形的宽
返回:
矩形的面积(长×宽)
"""
area = length * width
return area
# 调用函数
result = calculate_rect_area(5, 3) # 传递参数 5(长)和 3(宽)
print(result) # 输出:15(5×3的结果)
二、函数的参数类型
Python 函数的参数类型灵活多样,支持位置参数、关键字参数、默认参数、可变参数等,可根据需求灵活组合。
1. 位置参数(Positional Arguments)
最基础的参数类型,必须按定义的顺序传递,且数量与函数声明一致。
def greet(name, age):
print(f"Hello, {name}! You are {age} years old.")
# 按位置传递参数(name=Alice, age=20)
greet("Alice", 20) # 输出:Hello, Alice! You are 20 years old.
# 顺序错误会导致逻辑错误
greet(20, "Alice") # 输出:Hello, 20! You are Alice years old.(错误)
2. 关键字参数(Keyword Arguments)
调用函数时通过 参数名=值 的形式传递,不依赖顺序,更清晰易读。
def greet(name, age):
print(f"Hello, {name}! You are {age} years old.")
# 用关键字参数传递(顺序可任意)
greet(age=20, name="Alice") # 输出:Hello, Alice! You are 20 years old.
混合使用:位置参数必须在关键字参数之前。
greet("Alice", age=20) # 合法(位置参数在前,关键字参数在后)
# greet(age=20, "Alice") # 报错(关键字参数不能在位置参数前)
3. 默认参数(Default Arguments)
定义函数时为参数指定默认值,调用时可省略该参数(使用默认值)。注意:默认参数必须放在位置参数之后。
def greet(name, age=18): # age的默认值为18
print(f"Hello, {name}! You are {age} years old.")
greet("Bob") # 省略age,使用默认值18 → 输出:Hello, Bob! You are 18 years old.
greet("Bob", 22) # 传递age=22 → 输出:Hello, Bob! You are 22 years old.
警告:默认参数的值若为可变对象(如列表、字典),可能导致意外行为(默认值在函数定义时初始化,而非每次调用时)。
def add_item(item, items=[]): # 危险:默认值是可变列表
items.append(item)
return items
print(add_item("apple")) # 第一次调用:['apple']
print(add_item("banana")) # 第二次调用:['apple', 'banana'](意外保留了之前的结果)
正确做法:默认值设为 None,在函数体内初始化可变对象。
def add_item(item, items=None):
if items is None:
items = [] # 每次调用时重新初始化列表
items.append(item)
return items
print(add_item("apple")) # ['apple']
print(add_item("banana")) # ['banana'](符合预期)
4. 可变参数(Variable Arguments)
用于接收不确定数量的参数,分为两种:*args(接收位置参数)和 **kwargs(接收关键字参数)。
(1)*args:接收多个位置参数,返回元组
def sum_numbers(*args): # *args 接收所有位置参数,打包为元组
print("参数类型:", type(args)) # <class 'tuple'>
total = 0
for num in args:
total += num
return total
print(sum_numbers(1, 2, 3)) # 传递3个参数 → 6
print(sum_numbers(10, 20, 30, 40)) # 传递4个参数 → 100
print(sum_numbers()) # 传递0个参数 → 0
可结合位置参数使用(*args 必须在位置参数之后):
def print_info(title, *args):
print(f"标题:{title}")
print(f"内容:{args}")
print_info("成绩", 90, 85, 95) # 标题:成绩;内容:(90, 85, 95)
(2)**kwargs:接收多个关键字参数,返回字典
def print_user(** kwargs): # **kwargs 接收所有关键字参数,打包为字典
print("参数类型:", type(kwargs)) # <class 'dict'>
for key, value in kwargs.items():
print(f"{key}: {value}")
print_user(name="Alice", age=20, gender="female")
# 输出:
# name: Alice
# age: 20
# gender: female
可结合其他参数使用(**kwargs 必须在所有参数最后):
def print_order(product, price, *args, **kwargs):
print(f"商品:{product},价格:{price}")
print(f"附加参数:{args}")
print(f"其他信息:{kwargs}")
print_order("手机", 3999, "赠品:耳机", color="黑色", brand="华为")
# 输出:
# 商品:手机,价格:3999
# 附加参数:('赠品:耳机',)
# 其他信息:{'color': '黑色', 'brand': '华为'}
5. 强制关键字参数
通过在参数列表中添加 *,强制后续参数必须用关键字传递(避免位置参数顺序错误)。
def calculate(a, b, *, op="add"): # * 之后的 op 必须用关键字传递
if op == "add":
return a + b
elif op == "sub":
return a - b
calculate(10, 5, op="add") # 合法(op用关键字传递)→ 15
# calculate(10, 5, "add") # 报错(op必须用关键字传递)
三、函数的返回值
函数通过 return 语句返回结果,特性如下:
1. 基本返回值
- 一个函数可返回任意类型的值(数字、字符串、列表、字典、甚至函数)。
- 执行到
return语句后,函数立即终止,后续代码不再执行。 - 无
return语句时,默认返回None。
def is_positive(num):
if num > 0:
return True # 返回布尔值
else:
return False
result = is_positive(5)
print(result) # True
def empty_return():
print("执行函数")
return # 等价于 return None
print(empty_return()) # 输出:执行函数 → None
2. 返回多个值
Python 函数可通过返回元组间接返回多个值,调用时可自动解包。
def get_user():
name = "Alice"
age = 20
gender = "female"
return name, age, gender # 本质返回元组 (name, age, gender)
# 解包接收多个返回值
user_name, user_age, user_gender = get_user()
print(user_name, user_age, user_gender) # Alice 20 female
四、函数的作用域(Scope)
作用域指变量的可访问范围,Python 中函数的作用域遵循LEGB 规则:
- L(Local):局部作用域(函数内部定义的变量)。
- E(Enclosing):嵌套作用域(外层函数的变量,用于嵌套函数)。
- G(Global):全局作用域(模块级定义的变量)。
- B(Built-in):内置作用域(Python 内置函数 / 变量,如
print、len)。
1. 局部变量与全局变量
- 局部变量:函数内部定义的变量,仅在函数内部可访问。
- 全局变量:函数外部定义的变量,可在模块内的所有函数中访问(但修改需用
global声明)。
# 全局变量
global_var = "我是全局变量"
def test_scope():
# 局部变量
local_var = "我是局部变量"
print(local_var) # 合法:访问局部变量
print(global_var) # 合法:访问全局变量
test_scope()
# print(local_var) # 报错:局部变量在函数外不可访问
# 修改全局变量(需用 global 声明)
def modify_global():
global global_var # 声明要修改的全局变量
global_var = "修改后的全局变量"
modify_global()
print(global_var) # 输出:修改后的全局变量(已被修改)
2. 非局部变量(nonlocal)
用于嵌套函数中,修改外层函数(非全局)的变量。
def outer():
outer_var = "外层变量"
def inner():
nonlocal outer_var # 声明要修改外层函数的变量
outer_var = "修改后的外层变量"
print("inner中的outer_var:", outer_var)
inner()
print("outer中的outer_var:", outer_var)
outer()
# 输出:
# inner中的outer_var: 修改后的外层变量
# outer中的outer_var: 修改后的外层变量(被inner修改)
五、函数作为对象(高阶函数)
在 Python 中,函数是一等公民(First-Class Citizen),可作为变量赋值、作为参数传递、作为返回值,这是高阶函数的基础。
1. 函数赋值给变量
def add(a, b):
return a + b
func = add # 将函数赋值给变量
print(func(2, 3)) # 5(通过变量调用函数)
2. 函数作为参数传递
def add(a, b):
return a + b
def multiply(a, b):
return a * b
# 高阶函数:接收函数作为参数
def calculate(func, a, b):
return func(a, b)
print(calculate(add, 2, 3)) # 5(调用add)
print(calculate(multiply, 2, 3)) # 6(调用multiply)
Python 内置的 map、filter 等函数就是典型的高阶函数:
# map:将函数应用于可迭代对象的每个元素
numbers = [1, 2, 3, 4]
result = map(lambda x: x * 2, numbers) # 用lambda定义匿名函数
print(list(result)) # [2, 4, 6, 8]
3. 函数作为返回值
def make_adder(n):
# 内部函数(闭包)
def adder(x):
return x + n
return adder # 返回内部函数
# 创建两个加法函数
add_5 = make_adder(5) # 每次调用加5
add_10 = make_adder(10) # 每次调用加10
print(add_5(3)) # 8(3+5)
print(add_10(3)) # 13(3+10)
六、匿名函数(lambda)
lambda 用于定义单行匿名函数,语法简洁,适合简单逻辑(复杂逻辑建议用 def 定义)。语法:lambda 参数: 表达式(表达式的结果即为返回值)。
# 用lambda定义加法函数(等价于 def add(a,b): return a+b)
add = lambda a, b: a + b
print(add(2, 3)) # 5
# 作为高阶函数的参数(常用场景)
numbers = [(1, 3), (4, 1), (2, 5)]
# 按元组的第二个元素排序
numbers.sort(key=lambda x: x[1])
print(numbers) # [(4, 1), (1, 3), (2, 5)]
七、装饰器(Decorator)
装饰器是修改函数功能的工具,可在不修改原函数代码的前提下,为函数添加额外功能(如日志、计时、权限校验等)。本质是一个接收函数作为参数,并返回新函数的高阶函数。
1. 基础装饰器
# 定义装饰器:为函数添加计时功能
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs) # 调用原函数
end_time = time.time()
print(f"{func.__name__} 执行时间:{end_time - start_time:.4f}秒")
return result # 返回原函数的结果
return wrapper
# 使用装饰器(@语法糖)
@timer
def slow_function(seconds):
time.sleep(seconds) # 模拟耗时操作
return "完成"
slow_function(1) # 调用被装饰的函数
# 输出:slow_function 执行时间:1.0012秒(额外添加的计时功能)
@timer等价于slow_function = timer(slow_function)。wrapper(*args, **kwargs)确保装饰器可适配任意参数的函数。
2. 带参数的装饰器
若装饰器需要自定义参数(如日志级别),需再嵌套一层函数。
def logger(level):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{level}] 调用函数:{func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
# 使用带参数的装饰器
@logger(level="INFO")
def add(a, b):
return a + b
add(2, 3) # 输出:[INFO] 调用函数:add → 返回5
八、递归函数
递归函数是在函数体内调用自身的函数,适合解决可分解为 “重复子问题” 的场景(如阶乘、斐波那契数列、树遍历等)。递归需满足两个条件:-** 基线条件 :终止递归的条件(避免无限递归)。- 递归条件 **:函数调用自身,且问题规模缩小。
示例:计算阶乘
def factorial(n):
# 基线条件:n=0或1时,阶乘为1
if n == 0 or n == 1:
return 1
# 递归条件:n! = n × (n-1)!
return n * factorial(n - 1)
print(factorial(5)) # 120(5×4×3×2×1)
注意:Python 递归深度有限制(默认约 1000 层),过深会导致 RecursionError。复杂场景建议用循环替代。
九、函数文档与注解
1. 文档字符串(docstring)
用三引号包裹的函数说明,可通过 help(函数名) 或 函数名.__doc__ 查看。
def area(radius):
"""计算圆的面积
参数:
radius: 圆的半径(正数)
返回:
圆的面积(π×radius²)
异常:
ValueError: 若radius为负数
"""
if radius < 0:
raise ValueError("半径不能为负数")
return 3.14159 * radius**2
help(area) # 查看文档
2. 函数注解(Function Annotations)
可选的类型提示,用于说明参数和返回值的预期类型(不影响代码执行,仅为提示)。
def add(a: int, b: int) -> int: # 注解:a和b为int,返回值为int
return a + b
add(2, 3) # 符合注解
add("2", "3") # 仍能执行(返回"23"),注解不强制类型检查
十、函数的最佳实践
- 单一职责:一个函数只做一件事,避免过大的函数体。
- 命名清晰:函数名应体现其功能(如
get_user、calculate_sum)。 - 参数不宜过多:参数过多会降低可读性,可考虑用字典或类封装。
- 避免全局变量:减少函数对全局变量的依赖,通过参数传递输入。
- 添加文档:复杂函数必须写 docstring,说明功能、参数、返回值。
- 处理异常:对可能出错的场景(如参数非法)添加异常处理。
总结
函数是 Python 编程的核心组件,通过封装逻辑实现代码复用。本文涵盖了函数的定义、参数类型(位置、关键字、默认、可变参数)、返回值、作用域、高阶函数、装饰器、递归等核心知识点。掌握这些内容,可编写更简洁、高效、可维护的 Python 代码。