函数是Python程序的基本组成单元,是组织代码、实现逻辑复用、降低复杂度的核心手段。Python的函数设计体现了“简洁、优雅、高效”的语言哲学:从灵活的参数传递机制、强大的装饰器,到支持函数式编程的Lambda表达式和高阶函数,Python的函数体系为开发者提供了丰富而强大的编程能力。本文将系统全面地梳理Python函数的核心知识点,从基础语法到高级特性,帮助初学者建立完整的知识体系,也为有经验的开发者提供深入的技术参考。
一、函数基础
1.1 函数定义与调用
# 函数定义:使用def关键字
def say_hello():
"""简单的问候函数"""
print("Hello, World!")
# 带参数的函数
def greet(name):
"""带参数的函数"""
print(f"Hello, {name}!")
# 带返回值的函数
def add(a, b):
"""返回两个数的和"""
return a + b
# 函数调用
say_hello()
greet("Python")
result = add(10, 20)
print(f"结果: {result}")
# 函数文档字符串
print(help(add))
print(add.__doc__)
1.2 函数返回值
# 返回单个值
def square(x):
return x ** 2
# 返回多个值(实际是返回元组)
def get_min_max(numbers):
return min(numbers), max(numbers)
# 无返回值(返回None)
def do_nothing():
pass # 隐式返回None
# 提前返回
def check_age(age):
if age < 0:
return # 提前退出,返回None
return age >= 18
# 返回列表
def get_even_numbers(limit):
return [i for i in range(limit) if i % 2 == 0]
# 返回字典
def get_person_info(name, age):
return {"name": name, "age": age}
# 使用示例
num = square(5)
print(f"平方: {num}")
min_val, max_val = get_min_max([1, 3, 5, 2, 4])
print(f"最小值: {min_val}, 最大值: {max_val}")
even_nums = get_even_numbers(10)
print(f"偶数: {even_nums}")
1.3 类型注解(Type Hints)
# Python 3.5+ 支持类型注解
from typing import List, Dict, Optional, Union, Tuple
# 基本类型注解
def add_numbers(a: int, b: int) -> int:
"""带类型注解的函数"""
return a + b
# 列表类型
def process_numbers(numbers: List[int]) -> List[int]:
return [n * 2 for n in numbers]
# 字典类型
def get_user_info(user_id: int) -> Dict[str, str]:
return {"id": str(user_id), "name": "张三"}
# 可选类型
def find_user(user_id: int) -> Optional[Dict[str, str]]:
if user_id == 1:
return {"name": "张三"}
return None
# 联合类型
def process_value(value: Union[int, str]) -> str:
return str(value)
# 元组类型
def get_coordinates() -> Tuple[int, int]:
return (10, 20)
# 自定义类型别名
UserId = int
UserInfo = Dict[str, str]
def get_user(uid: UserId) -> UserInfo:
return {"id": str(uid), "name": "用户"}
# 类型注解不影响运行时
result = add_numbers(10, 20)
print(result)
二、参数传递
2.1 位置参数与关键字参数
# 位置参数:按位置传递
def describe_pet(name, animal_type):
print(f"我有一只{animal_type},名字叫{name}")
# 关键字参数:按名称传递
describe_pet(name="旺财", animal_type="狗")
describe_pet(animal_type="猫", name="咪咪")
# 混合使用:位置参数必须在关键字参数之前
describe_pet("小黑", animal_type="兔子")
# 默认参数
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("张三") # 使用默认问候语
greet("李四", "Hi") # 自定义问候语
# 默认参数陷阱:不要使用可变对象作为默认值
# 错误示例
def add_item(item, lst=[]): # 危险!默认列表会被共享
lst.append(item)
return lst
# 正确示例
def add_item_correct(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
print(add_item_correct(1)) # [1]
print(add_item_correct(2)) # [2] 不会被共享
2.2 可变参数
# *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(10, 20, 30, 40)) # 100
# **kwargs:接收任意多个关键字参数(字典)
def print_info(**kwargs):
"""打印关键字参数"""
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="张三", age=25, city="北京")
# 混合使用
def process_data(name, *args, **kwargs):
print(f"姓名: {name}")
print(f"位置参数: {args}")
print(f"关键字参数: {kwargs}")
process_data("张三", 1, 2, 3, age=25, city="北京")
# 解包参数
numbers = [1, 2, 3, 4, 5]
print(sum_all(*numbers)) # 解包列表
info = {"name": "李四", "age": 30}
print_info(**info) # 解包字典
2.3 参数解包
# 序列解包
def add_three(a, b, c):
return a + b + c
numbers = [10, 20, 30]
result = add_three(*numbers)
print(f"解包列表: {result}")
# 字典解包
def describe_person(name, age, city):
print(f"{name},{age}岁,来自{city}")
person_info = {"name": "张三", "age": 25, "city": "北京"}
describe_person(**person_info)
# 混合解包
def mixed_params(a, b, *args, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"kwargs={kwargs}")
list_args = [1, 2, 3, 4]
dict_kwargs = {"x": 10, "y": 20}
mixed_params(100, 200, *list_args, **dict_kwargs)
2.4 特殊参数(Python 3.8+)
# / 表示位置参数(不能使用关键字传递)
def func1(a, b, /, c, d):
"""a, b必须使用位置参数;c, d可以使用位置或关键字"""
print(a, b, c, d)
func1(1, 2, 3, 4) # 正确
func1(1, 2, c=3, d=4) # 正确
# func1(a=1, b=2, c=3, d=4) # 错误:a,b不能使用关键字
# * 表示关键字参数(必须使用关键字传递)
def func2(a, b, *, c, d):
"""a, b可以使用位置或关键字;c, d必须使用关键字"""
print(a, b, c, d)
func2(1, 2, c=3, d=4) # 正确
# func2(1, 2, 3, 4) # 错误:c,d必须使用关键字
# 组合使用
def func3(a, b, /, c, *, d, e):
"""
a, b: 位置参数
c: 位置或关键字
d, e: 关键字参数
"""
print(a, b, c, d, e)
func3(1, 2, 3, d=4, e=5) # 正确
三、函数作用域
3.1 局部变量与全局变量
# 全局变量
global_var = "我是全局变量"
def my_function():
# 局部变量
local_var = "我是局部变量"
print(f"函数内: {local_var}")
print(f"函数内访问全局: {global_var}")
my_function()
# print(local_var) # 错误:局部变量在函数外不可见
# 修改全局变量
counter = 0
def increment():
global counter # 声明使用全局变量
counter += 1
increment()
increment()
print(f"counter = {counter}")
# 全局变量与局部变量同名
name = "张三"
def show_name():
name = "李四" # 这是局部变量
print(f"函数内: {name}")
show_name()
print(f"函数外: {name}")
# globals()和locals()函数
x = 10
def test():
y = 20
print("全局变量:", globals())
print("局部变量:", locals())
test()
3.2 嵌套函数与闭包
# 嵌套函数
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
# 闭包:内部函数引用外部函数的变量
def make_multiplier(n):
"""创建一个乘数函数"""
def multiplier(x):
return x * n
return multiplier
times_2 = make_multiplier(2)
times_3 = make_multiplier(3)
print(times_2(10)) # 20
print(times_3(10)) # 30
# 闭包的实际应用:计数器
def make_counter():
count = 0
def counter():
nonlocal count # 声明使用外部变量(非全局)
count += 1
return count
return counter
counter1 = make_counter()
counter2 = make_counter()
print(counter1()) # 1
print(counter1()) # 2
print(counter2()) # 1(独立的计数器)
# nonlocal关键字
def outer():
x = "outer"
def inner():
nonlocal x # 修改外部函数的变量
x = "inner"
print(f"inner: {x}")
inner()
print(f"outer: {x}")
outer()
3.3 LEGB规则
# LEGB: Local -> Enclosing -> Global -> Built-in
# 1. Local(局部)
def func():
x = "local" # 局部作用域
print(x)
# 2. Enclosing(闭包)
def outer():
x = "enclosing"
def inner():
print(x) # 查找闭包作用域
inner()
# 3. Global(全局)
x = "global"
def func2():
print(x) # 查找全局作用域
# 4. Built-in(内置)
print(len("hello")) # len是内置函数
# 演示查找顺序
def demonstrate_legb():
x = "local"
def inner():
# 注释掉以下行来测试不同层级
x = "inner_local"
print(x)
inner()
demonstrate_legb()