ITPub博客

首页 > 应用开发 > Python > 人工智能之编程基础 Python 入门:第八章 函数与装饰器

人工智能之编程基础 Python 入门:第八章 函数与装饰器

原创 Python 作者:咚咚王者 时间:2025-11-17 19:45:18 0 删除 编辑

人工智能之编程基础 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))        # 6print(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 // 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

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 = 0def 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 ** 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 三元运算符除外)


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))  # 10print(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@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!

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):    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: 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)

2. 常用内置类型

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]

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 + 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, 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 = 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@decoratordef my_function():    print("原函数执行")

等价于:

my_function = decorator(my_function)

2. 简单装饰器示例

1. 计时装饰器

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()  # 会打印执行时间

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@loggerdef 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)@CountCallsdef 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_decoratordef 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 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 ** 2c = Circle(5)print(c.area)  # 78.53975c.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@decorator3def func():    pass# 等价于func = decorator1(decorator2(decorator3(func)))

2. 装饰器的副作用

  • 可能影响性能
  • 增加调试复杂度
  • 可能隐藏错误

3. 避免过度使用

装饰器应该用于:

  • 横切关注点(日志、权限、缓存等)
  • 通用功能
  • 不要用于业务逻辑

总结

本文主要对函数进行全方位的解析以及叙述,关于文中提到的类泛型等新的概念需要学习后续文章,有编程基础的可以快速掌握,对于没有基础的可以将新的概念词保留,以便后续的学习补充。

资料关注

相关资料获取:
公众号:咚咚王

艺术二维码.png

《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/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
深耕人工智能领域,做你的随身笔记。

注册时间:2025-10-26

  • 博文量
    47
  • 访问量
    46037