第八章 函数与装饰器
本章节主要学习 python 函数,从多个角度对函数进行学习,以便于熟练掌握。
在 Python 中, 函数(Function) 是组织代码、实现特定功能的基本单元。它是可重用的代码块,可以接受输入参数并返回结果。
def function_name(parameters): """文档字符串(可选)""" # 函数体 return value # 可选# 调用函数result = function_name(arguments)
def greet(name): """打招呼函数"""
print(f"Hello, {name}!")
greet("Alice") # 输出: Hello, Alice!
| 部分 | 说明 |
|---|---|
def 关键字 |
定义函数的开始 |
| 函数名 | 遵循变量命名规则,通常使用小写字母和下划线 |
| 参数列表 | 括号内的参数,可以为空 |
冒号
: |
表示函数体开始 |
| 函数体 | 缩进的代码块,实现具体功能 |
return 语句 |
返回结果,可选 |
| 文档字符串(docstring) | 用三引号括起的说明文字 |
def power(base, exponent): return base ** exponent result = power(2, 3) # 8
def greet(name, greeting="Hello"): return f"{greeting}, {name}!"print(greet("Alice")) # Hello, Alice!print(greet("Bob", "Hi")) # Hi, Bob!
注意:默认参数必须在非默认参数之后
def create_user(name, age, city): return {"name": name, "age": age, "city": city}
user = create_user(city="Beijing", name="Alice", age=25)
def sum_all(*args): """计算任意数量参数的和""" return sum(args)print(sum_all(1, 2, 3)) # 6print(sum_all(1, 2, 3, 4, 5)) # 15
def print_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")
print_info(name="Alice", age=25, city="Shanghai")
def func(a, b, *args, c=10, **kwargs): print(f"a={a}, b={b}") print(f"args={args}") print(f"c={c}") print(f"kwargs={kwargs}")
func(1, 2, 3, 4, c=20, x=100, y=200)
def square(x): return x ** 2result = square(4) # 16
def divide(a, b): quotient = a // b remainder = a % b return quotient, remainder # 返回元组q, r = divide(10, 3) # q=3, r=1
def say_hello(): print("Hello!") # 隐式返回 Noneresult = say_hello() # 输出: Hello!print(result) # None
Python 有四种作用域(LEGB 规则):
# 1. Local (局部)def outer(): x = "outer" # enclosing def inner(): x = "inner" # local print(x) # inner inner() print(x) # outer# 2. Enclosing (嵌套)def make_counter(): count = 0 # enclosing def counter(): nonlocal count count += 1 return count return counter# 3. Global (全局)global_var = "I'm global"def func(): print(global_var) # 可以读取 # global_var = "modified" # 错误!需要 global 关键字# 4. Built-in (内置)# len, print, range 等
global 和
nonlocal 关键字# global - 修改全局变量counter = 0def increment(): global counter counter += 1# nonlocal - 修改外层函数的变量def outer(): x = 10 def inner(): nonlocal x x += 1 inner() print(x) # 11
使用
lambda 创建简单的匿名函数:
# 语法: lambda 参数: 表达式square = lambda x: x ** 2print(square(5)) # 25# 常用于高阶函数numbers = [1, 2, 3, 4, 5] squared = list(map(lambda x: x**2, numbers)) evens = list(filter(lambda x: x % 2 == 0, numbers))# 排序pairs = [(1, 'b'), (2, 'a'), (3, 'c')] sorted_pairs = sorted(pairs, key=lambda x: x[1])
限制:lambda 只能包含表达式,不能有语句(如
if-else三元运算符除外)
函数可以作为参数传递或作为返回值:
# 函数作为参数def apply_operation(func, x, y): return func(x, y)def add(a, b): return a + b result = apply_operation(add, 3, 4) # 7# 函数作为返回值def make_multiplier(factor): def multiplier(x): return x * factor return multiplier double = make_multiplier(2) triple = make_multiplier(3)print(double(5)) # 10print(triple(5)) # 15
装饰器是修改函数行为的强大工具:
# 基本装饰器def timer(func): import time def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time() print(f"{func.__name__} 执行时间: {end - start:.4f}秒") return result return wrapper@timerdef slow_function(): import time
time.sleep(1)
slow_function() # 会打印执行时间# 带参数的装饰器def repeat(times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(times):
result = func(*args, **kwargs) return result return wrapper return decorator@repeat(3)def say_hello(): print("Hello!")
say_hello() # 打印三次 Hello!
函数调用自身:
# 计算阶乘def factorial(n): if n <= 1: return 1 return n * factorial(n - 1)print(factorial(5)) # 120# 斐波那契数列def fibonacci(n): if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2)
注意:递归需要有 基准条件,否则会导致无限递归和栈溢出
def add(a, b): """ 计算两个数的和 Args: a (int): 第一个数 b (int): 第二个数 Returns: int: 两数之和 Example: >>> add(2, 3) 5 """ return a + b
# ❌ 不好的做法def process_data(data): # 既读取又处理又保存 pass# ✅ 好的做法def read_data(filename): passdef clean_data(data): passdef save_data(data, filename): pass
from typing import List, Dictdef greet_users(names: List[str]) -> List[str]: return [f"Hello, {name}!" for name in names]
Python 提供了许多有用的内置函数:
# map() - 对每个元素应用函数numbers = [1, 2, 3, 4] squared = list(map(lambda x: x**2, numbers))# filter() - 过滤元素evens = list(filter(lambda x: x % 2 == 0, numbers))# reduce() - 累积计算from functools import reduce total = reduce(lambda x, y: x + y, numbers)# sorted() - 排序sorted_data = sorted(data, key=lambda x: x[1])
类型注解(Type Hints) 是一种为变量、函数参数和返回值指定预期数据类型的语法。它从 Python 3.5 开始引入(PEP 484),旨在提高代码的可读性、可维护性,并支持静态类型检查工具。
# 基本语法: variable: typename: str = "Alice"age: int = 25height: float = 1.75is_student: bool = False
def greet(name: str, age: int) -> str: return f"Hello, {name}! You are {age} years old."result: str = greet("Bob", 30)
from typing import List, Dict, Tuple, Set, Optional, Union, Any# 基本类型x: int = 1y: float = 3.14z: str = "hello"flag: bool = True# 容器类型numbers: List[int] = [1, 2, 3, 4]
names: List[str] = ["Alice", "Bob"]
mixed_list: List[Union[int, str]] = [1, "hello", 2, "world"]# 字典person: Dict[str, Any] = {"name": "Alice", "age": 25}
config: Dict[str, str] = {"host": "localhost", "port": "8080"}# 元组coordinates: Tuple[float, float] = (3.5, 4.2)
person_data: Tuple[str, int, bool] = ("Alice", 25, True)# 集合unique_ids: Set[int] = {1, 2, 3, 4}
注意:从 Python 3.9+ 开始,可以直接使用内置类型:
numbers: list[int] = [1, 2, 3] # 而不是 List[int]config: dict[str, str] = {...} # 而不是 Dict[str, str]unique_ids: set[int] = {1, 2, 3} # 而不是 Set[int]
Optional[T] - 可选类型表示值可以是
T 类型或
None
from typing import Optionaldef find_user(user_id: int) -> Optional[str]: """如果找到用户返回用户名,否则返回 None""" if user_id == 1: return "Alice" return None# 等价于 Union[str, None]
Union[T1, T2, ...] - 联合类型表示值可以是多种类型之一
from typing import Uniondef process_value(value: Union[int, str]) -> str: if isinstance(value, int): return f"Number: {value}"
else: return f"String: {value}"# Python 3.10+ 可以使用 | 操作符def process_value_v2(value: int | str) -> str:
...
Any - 任意类型from typing import Anydef process_anything(data: Any) -> Any: """接受任何类型,返回任何类型""" return data
NoReturn - 无返回表示函数永远不会正常返回
from typing import NoReturndef raise_error() -> NoReturn: raise Exception("This function always raises an exception")
Callable - 可调用对象from typing import Callabledef apply_function(func: Callable[[int, int], int], a: int, b: int) -> int: return func(a, b)def add(x: int, y: int) -> int: return x + y result = apply_function(add, 3, 4) # 7
# 列表的字典data: Dict[str, List[int]] = { "scores": [85, 90, 78], "ranks": [1, 2, 3]
}# 元组的列表points: List[Tuple[float, float]] = [(0.0, 0.0), (1.0, 1.0)]# 字典的字典users: Dict[str, Dict[str, Union[str, int]]] = { "alice": {"name": "Alice", "age": 25}, "bob": {"name": "Bob", "age": 30}
}
from typing import TypeVar, GenericT = TypeVar('T')class Stack(Generic[T]): def __init__(self) -> None:
self._items: List[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T: return self._items.pop()# 使用int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
为复杂类型创建别名,提高可读性:
from typing import List, Tuple# 创建类型别名Vector = List[float] Point = Tuple[float, float] Matrix = List[Vector]def scale_vector(v: Vector, factor: float) -> Vector: return [x * factor for x in v]def distance(p1: Point, p2: Point) -> float: return ((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)**0.5
from typing import Optional, Listclass Person: def __init__(self, name: str, age: int) -> None:
self.name: str = name
self.age: int = age
self.hobbies: List[str] = []
def add_hobby(self, hobby: str) -> None:
self.hobbies.append(hobby)
def get_info(self) -> str: return f"{self.name}, {self.age}岁"
@property
def is_adult(self) -> bool: return self.age >= 18
类型注解本身 不会在运行时强制执行,需要配合静态检查工具:
# 安装pip install mypy# 检查文件mypy your_script.py
def add_numbers(a: int, b: int) -> int: return a + b# mypy 会报错:Argument 1 has incompatible type "str"; expected "int"result = add_numbers("hello", 5)
现代 IDE(如 PyCharm、VS Code)都能利用类型注解提供:
✅ 建议使用:
❌ 可以省略:
# ✅ 好的做法def calculate_area(length: float, width: float) -> float: """计算矩形面积""" return length * width# ❌ 不一致的做法def calculate_area(length, width): # 参数无类型 return length * width # 返回值无类型
def process_data(data: List[Dict[str, Any]], filter_key: str, filter_value: Any) -> List[Dict[str, Any]]: """ 处理数据列表,根据键值过滤 Args: data: 数据列表,每个元素是字典 filter_key: 要过滤的键 filter_value: 过滤值 Returns: 过滤后的数据列表 """ return [item for item in data if item.get(filter_key) == filter_value]
|# 旧方式def process_value(value: Union[int, str]) -> str: ...# 新方式 (Python 3.10+)def process_value(value: int | str) -> str: ...
# Python 3.10+def func(values: list[int | str]) -> None: ...
装饰器(Decorator) 是一种强大的设计模式,它允许你在不修改原函数代码的情况下,为函数添加新的功能或行为。装饰器本质上是一个 接收函数作为参数并返回函数的高阶函数。
装饰器遵循 开放-封闭原则:对扩展开放,对修改封闭。
# 基本结构def decorator(func): def wrapper(*args, **kwargs): # 调用前的操作
result = func(*args, **kwargs) # 调用后的操作
return result return wrapper@decoratordef my_function(): print("原函数执行")
等价于:
my_function = decorator(my_function)
import timefrom functools import wrapsdef timer(func): @wraps(func) # 保留原函数的元数据
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time() print(f"{func.__name__} 执行时间: {end - start:.4f}秒") return result return wrapper@timerdef slow_function():
time.sleep(1) return "完成"slow_function() # 会打印执行时间
def logger(func): @wraps(func)
def wrapper(*args, **kwargs): print(f"调用函数: {func.__name__}") print(f"参数: args={args}, kwargs={kwargs}")
result = func(*args, **kwargs) print(f"{func.__name__} 返回: {result}") return result return wrapper@loggerdef add(a, b): return a + b
add(3, 4)
装饰器本身也可以接受参数:
def repeat(times): """重复执行函数指定次数"""
def decorator(func): @wraps(func)
def wrapper(*args, **kwargs): for _ in range(times):
result = func(*args, **kwargs) return result return wrapper return decorator@repeat(3)def say_hello(): print("Hello!")
say_hello() # 打印三次 Hello!
def retry(max_attempts=3, delay=1): """失败时重试"""
def decorator(func): @wraps(func)
def wrapper(*args, **kwargs): for attempt in range(max_attempts): try: return func(*args, **kwargs) except Exception as e: if attempt == max_attempts - 1: raise e print(f"第{attempt + 1}次尝试失败: {e}, {delay}秒后重试")
time.sleep(delay) return wrapper return decorator@retry(max_attempts=3, delay=0.5)def unstable_api(): import random if random.random() < 0.7: # 70% 概率失败
raise ConnectionError("网络错误") return "成功"
类也可以作为装饰器:
class CountCalls: def __init__(self, func):
self.func = func
self.count = 0
wraps(func)(self) # 复制原函数的元数据
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} 被调用了 {self.count} 次") return self.func(*args, **kwargs)@CountCallsdef greet(name): print(f"Hello, {name}!")
greet("Alice") # 被调用了 1 次greet("Bob") # 被调用了 2 次
可以将多个装饰器堆叠使用:
@timer@logger@repeat(2)def calculate_sum(n): return sum(range(n)) calculate_sum(1000)
执行顺序:
从下到上(先
repeat,再
logger,最后
timer)
使用
@wraps 非常重要,否则会丢失原函数的信息:
from functools import wrapsdef simple_decorator(func): @wraps(func) # 保留 __name__, __doc__, __module__ 等 def wrapper(*args, **kwargs): """wrapper 函数的文档""" return func(*args, **kwargs) return wrapper@simple_decoratordef original_function(): """原函数的文档""" passprint(original_function.__name__) # original_function (而不是 wrapper)print(original_function.__doc__) # 原函数的文档 (而不是 wrapper 的文档)
from functools import lru_cache@lru_cache(maxsize=128)def fibonacci(n): if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2)# 内置的 lru_cache 是一个优秀的缓存装饰器
def requires_permission(permission): def decorator(func): @wraps(func)
def wrapper(user, *args, **kwargs): if permission not in user.get('permissions', []): raise PermissionError(f"需要 {permission} 权限") return func(user, *args, **kwargs) return wrapper return decorator@requires_permission('admin')def delete_user(user, target_user): print(f"删除用户: {target_user}")
admin = {'name': 'admin', 'permissions': ['admin', 'user']}
delete_user(admin, 'test_user') # 成功
def validate_types(**expected_types): def decorator(func): @wraps(func)
def wrapper(*args, **kwargs): # 获取函数签名
import inspect
sig = inspect.signature(func)
bound_args = sig.bind(*args, **kwargs)
bound_args.apply_defaults()
# 验证类型
for name, value in bound_args.arguments.items(): if name in expected_types: if not isinstance(value, expected_types[name]): raise TypeError(f"{name} 必须是 {expected_types[name]} 类型")
return func(*args, **kwargs) return wrapper return decorator@validate_types(age=int, name=str)def create_user(name, age): return f"用户 {name}, {age}岁"create_user("Alice", 25) # 正常# create_user("Bob", "25") # 抛出 TypeError
class Circle: def __init__(self, radius):
self._radius = radius
@property
def radius(self): return self._radius
@radius.setter
def radius(self, value): if value < 0: raise ValueError("半径不能为负数")
self._radius = value
@property
def area(self): return 3.14159 * self._radius ** 2c = Circle(5)print(c.area) # 78.53975c.radius = 10 # 使用 setter
创建可配置的装饰器:
def create_validator(min_value=None, max_value=None, type_=None): def validator(func): @wraps(func)
def wrapper(value): if type_ and not isinstance(value, type_): raise TypeError(f"必须是 {type_} 类型") if min_value is not None and value < min_value: raise ValueError(f"值不能小于 {min_value}") if max_value is not None and value > max_value: raise ValueError(f"值不能大于 {max_value}") return func(value) return wrapper return validator@create_validator(min_value=0, max_value=100, type_=int)def set_grade(grade): print(f"成绩设置为: {grade}")
set_grade(85) # 正常# set_grade(-5) # 抛出 ValueError
@decorator1@decorator2@decorator3def func(): pass# 等价于func = decorator1(decorator2(decorator3(func)))
装饰器应该用于:
本文主要对函数进行全方位的解析以及叙述,关于文中提到的类泛型等新的概念需要学习后续文章,有编程基础的可以快速掌握,对于没有基础的可以将新的概念词保留,以便后续的学习补充。
相关资料获取:
公众号:咚咚王

《Python 编程:从入门到实践》
《利用 Python 进行数据分析》
《算法导论中文第三版》
《概率论与数理统计(第四版) (盛骤) 》
《程序员的数学》
《线性代数应该这样学第 3 版》
《微积分和数学分析引论》
《(西瓜书)周志华-机器学习》
《TensorFlow 机器学习实战指南》
《Sklearn 与 TensorFlow 机器学习实用指南》
《模式识别(第四版)》
《深度学习 deep learning》伊恩·古德费洛著 花书
《Python 深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》
《深入浅出神经网络与深度学习 +(迈克尔·尼尔森(Michael+Nielsen) 》
《自然语言处理综论 第 2 版》
《Natural-Language-Processing-with-PyTorch》
《计算机视觉-算法与应用(中文版)》
《Learning OpenCV 4》
《AIGC:智能创作时代》杜雨 +&+ 张孜铭
《AIGC 原理与实践:零基础学大语言模型、扩散模型和多模态模型》
《从零构建大语言模型(中文版)》
《实战 AI 大模型》
《AI 3.0》
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048224/viewspace-3102015/ ,如需转载,请注明出处,否则将追究法律责任。