人工智能之编程基础 Python 入门
第八章 函数与装饰器
@
前言
本章节主要学习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 ** exponent
result = 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 ** 2
result = 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!")
# 隐式返回 None
result = say_hello() # 输出: Hello!
print(result) # None
5. 变量作用域
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 = 0
def increment():
global counter
counter += 1
# nonlocal - 修改外层函数的变量
def outer():
x = 10
def inner():
nonlocal x
x += 1
inner()
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 + 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)) # 10
print(triple(5)) # 15
8. 装饰器(Decorator)
装饰器是修改函数行为的强大工具:
# 基本装饰器
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
@timer
def 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!
9. 递归函数
函数调用自身:
# 计算阶乘
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)
注意:递归需要有基准条件,否则会导致无限递归和栈溢出
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):
pass
def clean_data(data):
pass
def save_data(data, filename):
pass
3. 使用类型提示(Python 3.5+)
from typing import List, Dict
def 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 Optional
def 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 Union
def 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 Any
def process_anything(data: Any) -> Any:
"""接受任何类型,返回任何类型"""
return data
NoReturn - 无返回
表示函数永远不会正常返回
from typing import NoReturn
def raise_error() -> NoReturn:
raise Exception("This function always raises an exception")
Callable - 可调用对象
from typing import Callable
def 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
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, Generic
T = 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, List
class 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
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 result
return wrapper
@decorator
def my_function():
print("原函数执行")
等价于:
my_function = decorator(my_function)
2. 简单装饰器示例
1. 计时装饰器
import time
from functools import wraps
def 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
@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 result
return wrapper
@logger
def add(a, b):
return a + b
add(3, 4)
3. 带参数的装饰器
装饰器本身也可以接受参数:
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 "成功"
4. 类装饰器
类也可以作为装饰器:
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)
@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 wraps
def simple_decorator(func):
@wraps(func) # 保留 __name__, __doc__, __module__ 等
def wrapper(*args, **kwargs):
"""wrapper 函数的文档"""
return func(*args, **kwargs)
return wrapper
@simple_decorator
def original_function():
"""原函数的文档"""
pass
print(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 n
return 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 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') # 成功
3. 输入验证
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
4. 属性装饰器
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 ** 2
c = 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 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
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》
posted on
浙公网安备 33010602011771号