人工智能之编程基础 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 等

globalnonlocal 关键字

# 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. 避免过度使用

装饰器应该用于:

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

总结

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

资料关注

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

艺术二维码.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》

 posted on 2025-11-17 19:42  咚咚王者  阅读(2)  评论(0)    收藏  举报