python中 @注解 及内置注解 的使用方法总结以及完整示例

发布于:2025-05-31 ⋅ 阅读:(21) ⋅ 点赞:(0)

在Python中,装饰器(Decorator) 使用 @ 符号实现,是一种修改函数/类行为的语法糖。它本质上是一个高阶函数,接受目标函数作为参数并返回包装后的函数。Python也提供了多个内置装饰器,如 @property@staticmethod@classmethod 等。


一、核心概念

  1. 装饰器本质@decorator 等价于 func = decorator(func)
  2. 执行时机:在函数/类定义时立即执行装饰器逻辑
  3. 链式装饰:多个装饰器按从下到上的顺序应用
    @decorator1
    @decorator2
    def func(): ...
    # 等价于:func = decorator1(decorator2(func))
    

二、自定义装饰器示例

1. 函数装饰器(无参数)
def logger(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@logger
def add(a, b):
    return a + b

print(add(3, 5))  
# 输出: 
#   调用函数: add
#   8
2. 带参数的装饰器
def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")
# 输出:
#   Hello, Alice!
#   Hello, Alice!
#   Hello, Alice!
3. 类装饰器
class CountCalls:
    def __init__(self, func):
        self.func = func
        self.calls = 0

    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"调用次数: {self.calls}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()  # 输出: 调用次数: 1 \n Hello!
say_hello()  # 输出: 调用次数: 2 \n Hello!

三、内置装饰器详解

1. @property:定义属性访问
class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        """Getter: 访问半径"""
        return self._radius

    @radius.setter
    def radius(self, value):
        """Setter: 设置半径(带验证)"""
        if value <= 0:
            raise ValueError("半径必须为正数")
        self._radius = value

    @property
    def area(self):
        """只读属性: 计算面积"""
        return 3.14 * self._radius ** 2

c = Circle(5)
print(c.radius)    # 5 (像属性一样调用)
c.radius = 10      # 调用setter
print(c.area)      # 314.0 (只读属性)
# c.area = 100     # 报错: AttributeError
2. @classmethod:类方法
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def from_string(cls, date_str):
        """工厂方法: 从字符串创建实例"""
        year, month, day = map(int, date_str.split('-'))
        return cls(year, month, day)  # cls指向类本身

    def __str__(self):
        return f"{self.year}-{self.month}-{self.day}"

d = Date.from_string("2023-10-01")
print(d)  # 2023-10-01
3. @staticmethod:静态方法
class MathUtils:
    @staticmethod
    def add(a, b):
        """与类相关但不需要类/实例参与的独立函数"""
        return a + b

print(MathUtils.add(3, 7))  # 10 (无需实例化)
4. @functools.wraps:保留元数据
import functools

def debug(func):
    @functools.wraps(func)  # 保留原函数名/文档等元数据
    def wrapper(*args, **kwargs):
        print(f"调试: {func.__name__}()")
        return func(*args, **kwargs)
    return wrapper

@debug
def example():
    """示例函数文档"""
    pass

print(example.__name__)  # "example" (不加wraps会显示"wrapper")
print(example.__doc__)   # "示例函数文档"

四、使用场景总结

装饰器类型 典型应用场景
自定义无参装饰器 日志记录、性能计时、权限验证
自定义带参装饰器 重复执行、超时控制、注册路由(如Flask)
@property 封装属性访问、添加验证逻辑、计算属性
@classmethod 工厂方法创建实例、操作类级别数据
@staticmethod 工具函数(与类相关但无需访问实例/类状态)
@functools.cache 缓存函数结果(Python 3.9+)

五、注意事项

  1. 装饰器会改变函数的__name__等元数据(用@functools.wraps修复)
  2. 多个装饰器顺序影响行为(最靠近函数的装饰器最先执行)
  3. @property必须定义在相同名称的@xxx.setter之前

掌握装饰器能大幅提升代码的复用性和可读性,是Python高级编程的核心技术之一。