人工智能之编程基础 Python 入门
第八章 函数与装饰器
@
目录
- 人工智能之编程基础 Python 入门
- 前言
- 函数
- 1. 函数的定义与调用
- 基本语法
- 简单示例
- 2. 函数的组成部分
- 3. 参数类型
- 1. 位置参数(Positional Arguments)
- 2. 默认参数(Default Arguments)
- 3. 关键字参数(Keyword Arguments)
- 4. 可变位置参数(*args)
- 5. 可变关键字参数(**kwargs)
- 6. 混合使用
- 4. 返回值
- 单个返回值
- 多个返回值(实际上是返回元组)
- 无返回值
- 5. 变量作用域
global和nonlocal关键字- 6. 匿名函数(Lambda)
- 7. 高阶函数
- 8. 装饰器(Decorator)
- 9. 递归函数
- 10. 函数的最佳实践
- 1. 使用文档字符串
- 2. 函数应该单一职责
- 3. 使用类型提示(Python 3.5+)
- 11. 内置高阶函数
- 类型注解
- 1. 基本类型注解
- 变量类型注解
- 函数参数和返回值注解
- 2. 常用内置类型
- 3. 特殊类型
Optional[T]- 可选类型Union[T1, T2, ...]- 联合类型Any- 任意类型NoReturn- 无返回Callable- 可调用对象- 4. 复杂类型示例
- 嵌套类型
- 泛型(Generic Types)
- 5. 类型别名(Type Aliases)
- 6. 类中的类型注解
- 7. 使用类型检查工具
- 1. mypy - 最流行的 Python 类型检查器
- 2. 示例检查
- 3. IDE 支持
- 8. 最佳实践
- 1. 何时使用类型注解
- 2. 保持一致性
- 3. 使用文档字符串配合
- 9. Python 3.10+ 的新特性
- 联合操作符
|- 带括号的联合类型
- 装饰器
- 1. 装饰器的基本概念
- 2. 简单装饰器示例
- 1. 计时装饰器
- 2. 日志装饰器
- 3. 带参数的装饰器
- 更复杂的参数装饰器
- 4. 类装饰器
- 5. 装饰器的堆叠
- 6. 保留函数元数据
- 7. 常见的装饰器应用场景
- 1. 缓存/记忆化
- 2. 权限验证
- 3. 输入验证
- 4. 属性装饰器
- 8. 装饰器工厂
- 9. 装饰器的注意事项
- 1. 执行顺序
- 2. 装饰器的副作用
- 3. 避免过度使用
- 总结
- 资料关注
前言
本章节主要学习python函数,从多个角度对函数进行学习,以便于熟练掌握。
函数
在 Python 中,函数(Function) 是组织代码、实现特定功能的基本单元。它是可重用的代码块,可以接受输入参数并返回结果。
1. 函数的定义与调用
基本语法
def function_name(parameters):"""文档字符串(可选)"""# 函数体return value # 可选# 调用函数
result = function_name(arguments)
简单示例
def greet(name):"""打招呼函数"""print(f"Hello, {name}!")greet("Alice") # 输出: Hello, Alice!
2. 函数的组成部分
| 部分 | 说明 |
|---|---|
def 关键字 |
定义函数的开始 |
| 函数名 | 遵循变量命名规则,通常使用小写字母和下划线 |
| 参数列表 | 括号内的参数,可以为空 |
冒号 : |
表示函数体开始 |
| 函数体 | 缩进的代码块,实现具体功能 |
return 语句 |
返回结果,可选 |
| 文档字符串(docstring) | 用三引号括起的说明文字 |
3. 参数类型
1. 位置参数(Positional Arguments)
def power(base, exponent):return base ** exponentresult = power(2, 3) # 8
2. 默认参数(Default Arguments)
def greet(name, greeting="Hello"):return f"{greeting}, {name}!"print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
注意:默认参数必须在非默认参数之后
3. 关键字参数(Keyword Arguments)
def create_user(name, age, city):return {"name": name, "age": age, "city": city}user = create_user(city="Beijing", name="Alice", age=25)
4. 可变位置参数(*args)
def sum_all(*args):"""计算任意数量参数的和"""return sum(args)print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
5. 可变关键字参数(**kwargs)
def print_info(**kwargs):for key, value in kwargs.items():print(f"{key}: {value}")print_info(name="Alice", age=25, city="Shanghai")
6. 混合使用
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)
4. 返回值
单个返回值
def square(x):return x ** 2result = square(4) # 16
多个返回值(实际上是返回元组)
def divide(a, b):quotient = a // bremainder = a % breturn quotient, remainder # 返回元组q, r = divide(10, 3) # q=3, r=1
无返回值
def say_hello():print("Hello!")# 隐式返回 Noneresult = say_hello() # 输出: Hello!
print(result) # None
5. 变量作用域
Python 有四种作用域(LEGB 规则):
# 1. Local (局部)
def outer():x = "outer" # enclosingdef inner():x = "inner" # localprint(x) # innerinner()print(x) # outer# 2. Enclosing (嵌套)
def make_counter():count = 0 # enclosingdef counter():nonlocal countcount += 1return countreturn 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 = 0
def increment():global countercounter += 1# nonlocal - 修改外层函数的变量
def outer():x = 10def inner():nonlocal xx += 1inner()print(x) # 11
6. 匿名函数(Lambda)
使用 lambda 创建简单的匿名函数:
# 语法: lambda 参数: 表达式
square = lambda x: x ** 2
print(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三元运算符除外)
7. 高阶函数
函数可以作为参数传递或作为返回值:
# 函数作为参数
def apply_operation(func, x, y):return func(x, y)def add(a, b):return a + bresult = apply_operation(add, 3, 4) # 7# 函数作为返回值
def make_multiplier(factor):def multiplier(x):return x * factorreturn multiplierdouble = make_multiplier(2)
triple = make_multiplier(3)print(double(5)) # 10
print(triple(5)) # 15
8. 装饰器(Decorator)
装饰器是修改函数行为的强大工具:
# 基本装饰器
def timer(func):import timedef wrapper(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time()print(f"{func.__name__} 执行时间: {end - start:.4f}秒")return resultreturn wrapper@timer
def slow_function():import timetime.sleep(1)slow_function() # 会打印执行时间# 带参数的装饰器
def repeat(times):def decorator(func):def wrapper(*args, **kwargs):for _ in range(times):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(3)
def say_hello():print("Hello!")say_hello() # 打印三次 Hello!
9. 递归函数
函数调用自身:
# 计算阶乘
def factorial(n):if n <= 1:return 1return n * factorial(n - 1)print(factorial(5)) # 120# 斐波那契数列
def fibonacci(n):if n <= 1:return nreturn fibonacci(n-1) + fibonacci(n-2)
注意:递归需要有基准条件,否则会导致无限递归和栈溢出
10. 函数的最佳实践
1. 使用文档字符串
def add(a, b):"""计算两个数的和Args:a (int): 第一个数b (int): 第二个数Returns:int: 两数之和Example:>>> add(2, 3)5"""return a + b
2. 函数应该单一职责
# ❌ 不好的做法
def process_data(data):# 既读取又处理又保存pass# ✅ 好的做法
def read_data(filename):passdef clean_data(data):passdef save_data(data, filename):pass
3. 使用类型提示(Python 3.5+)
from typing import List, Dictdef greet_users(names: List[str]) -> List[str]:return [f"Hello, {name}!" for name in names]
11. 内置高阶函数
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),旨在提高代码的可读性、可维护性,并支持静态类型检查工具。
1. 基本类型注解
变量类型注解
# 基本语法: variable: type
name: str = "Alice"
age: int = 25
height: float = 1.75
is_student: bool = False
函数参数和返回值注解
def greet(name: str, age: int) -> str:return f"Hello, {name}! You are {age} years old."result: str = greet("Bob", 30)
2. 常用内置类型
from typing import List, Dict, Tuple, Set, Optional, Union, Any# 基本类型
x: int = 1
y: float = 3.14
z: 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]
3. 特殊类型
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 + yresult = apply_function(add, 3, 4) # 7
4. 复杂类型示例
嵌套类型
# 列表的字典
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}
}
泛型(Generic Types)
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)
5. 类型别名(Type Aliases)
为复杂类型创建别名,提高可读性:
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
6. 类中的类型注解
from typing import Optional, Listclass Person:def __init__(self, name: str, age: int) -> None:self.name: str = nameself.age: int = ageself.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}岁"@propertydef is_adult(self) -> bool:return self.age >= 18
7. 使用类型检查工具
类型注解本身不会在运行时强制执行,需要配合静态检查工具:
1. mypy - 最流行的 Python 类型检查器
# 安装
pip install mypy# 检查文件
mypy your_script.py
2. 示例检查
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)
3. IDE 支持
现代 IDE(如 PyCharm、VS Code)都能利用类型注解提供:
- 自动补全
- 错误提示
- 代码导航
8. 最佳实践
1. 何时使用类型注解
✅ 建议使用:
- 公共 API
- 复杂函数
- 团队项目
- 长期维护的代码
❌ 可以省略:
- 简单的脚本
- Jupyter Notebook
- 快速原型
2. 保持一致性
# ✅ 好的做法
def calculate_area(length: float, width: float) -> float:"""计算矩形面积"""return length * width# ❌ 不一致的做法
def calculate_area(length, width): # 参数无类型return length * width # 返回值无类型
3. 使用文档字符串配合
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]
9. Python 3.10+ 的新特性
联合操作符 |
# 旧方式
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) 是一种强大的设计模式,它允许你在不修改原函数代码的情况下,为函数添加新的功能或行为。装饰器本质上是一个接收函数作为参数并返回函数的高阶函数。
1. 装饰器的基本概念
装饰器遵循开放-封闭原则:对扩展开放,对修改封闭。
# 基本结构
def decorator(func):def wrapper(*args, **kwargs):# 调用前的操作result = func(*args, **kwargs)# 调用后的操作return resultreturn wrapper@decorator
def my_function():print("原函数执行")
等价于:
my_function = decorator(my_function)
2. 简单装饰器示例
1. 计时装饰器
import time
from 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 resultreturn wrapper@timer
def slow_function():time.sleep(1)return "完成"slow_function() # 会打印执行时间
2. 日志装饰器
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 resultreturn wrapper@logger
def add(a, b):return a + badd(3, 4)
3. 带参数的装饰器
装饰器本身也可以接受参数:
def repeat(times):"""重复执行函数指定次数"""def decorator(func):@wraps(func)def wrapper(*args, **kwargs):for _ in range(times):result = func(*args, **kwargs)return resultreturn wrapperreturn 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 eprint(f"第{attempt + 1}次尝试失败: {e}, {delay}秒后重试")time.sleep(delay)return wrapperreturn decorator@retry(max_attempts=3, delay=0.5)
def unstable_api():import randomif random.random() < 0.7: # 70% 概率失败raise ConnectionError("网络错误")return "成功"
4. 类装饰器
类也可以作为装饰器:
class CountCalls:def __init__(self, func):self.func = funcself.count = 0wraps(func)(self) # 复制原函数的元数据def __call__(self, *args, **kwargs):self.count += 1print(f"{self.func.__name__} 被调用了 {self.count} 次")return self.func(*args, **kwargs)@CountCalls
def greet(name):print(f"Hello, {name}!")greet("Alice") # 被调用了 1 次
greet("Bob") # 被调用了 2 次
5. 装饰器的堆叠
可以将多个装饰器堆叠使用:
@timer
@logger
@repeat(2)
def calculate_sum(n):return sum(range(n))calculate_sum(1000)
执行顺序:从下到上(先 repeat,再 logger,最后 timer)
6. 保留函数元数据
使用 @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_decorator
def original_function():"""原函数的文档"""passprint(original_function.__name__) # original_function (而不是 wrapper)
print(original_function.__doc__) # 原函数的文档 (而不是 wrapper 的文档)
7. 常见的装饰器应用场景
1. 缓存/记忆化
from functools import lru_cache@lru_cache(maxsize=128)
def fibonacci(n):if n <= 1:return nreturn fibonacci(n-1) + fibonacci(n-2)# 内置的 lru_cache 是一个优秀的缓存装饰器
2. 权限验证
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 wrapperreturn 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') # 成功
3. 输入验证
def validate_types(**expected_types):def decorator(func):@wraps(func)def wrapper(*args, **kwargs):# 获取函数签名import inspectsig = 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 wrapperreturn 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
4. 属性装饰器
class Circle:def __init__(self, radius):self._radius = radius@propertydef radius(self):return self._radius@radius.setterdef radius(self, value):if value < 0:raise ValueError("半径不能为负数")self._radius = value@propertydef area(self):return 3.14159 * self._radius ** 2c = Circle(5)
print(c.area) # 78.53975
c.radius = 10 # 使用 setter
8. 装饰器工厂
创建可配置的装饰器:
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 wrapperreturn 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
9. 装饰器的注意事项
1. 执行顺序
@decorator1
@decorator2
@decorator3
def func():pass# 等价于
func = decorator1(decorator2(decorator3(func)))
2. 装饰器的副作用
- 可能影响性能
- 增加调试复杂度
- 可能隐藏错误
3. 避免过度使用
装饰器应该用于:
- 横切关注点(日志、权限、缓存等)
- 通用功能
- 不要用于业务逻辑
总结
本文主要对函数进行全方位的解析以及叙述,关于文中提到的类泛型等新的概念需要学习后续文章,有编程基础的可以快速掌握,对于没有基础的可以将新的概念词保留,以便后续的学习补充。
资料关注
相关资料获取:
公众号:咚咚王

《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》