开发者

Python装饰器之类装饰器详解

目录
  • 1. 引言
  • 2. 装饰器的基本概念
    • 2.1. 函数装饰器复习
    • 2.2 类装饰器的定义和使用
  • 3. 类装饰器的应用场景
    • 3.1. 自动添加属性
    • 3.2 访问控制
    • 3.3 数据验证
  • 4. 综合示例
    • 4.1 输出结果
    • 4.2 解释
  • 总结

    1. 引言

    在python中,装饰器是一种允许我们在不改变原有代码的情况下,动态地增加或修改函数和类功能的工具。

    类装饰器相较于函数装饰器,功能更为强大和灵活,因为它们不仅可以修饰类的方法,还可以修饰类本身。

    2. 装饰器的基本概念

    装饰器是一个接受函数或类并返回一个新函数或新类的高阶函数。它们通常通过 @ 符号来使用。

    在使用装饰器时,我们将装饰器放在被装饰对象的上方,这样装饰器就会在对象创建时自动应用。

    2.1. 函数装饰器复习

    在介绍类装饰器之前,我们先简单回顾一下函数装饰器的基本用法。

    def my_decorator(func):
        def wrapper(*args, **kwargs):
            print("Something is happening before the function is called.")
            result = func(*args, **kwargs)
            print("Something is happening after the function is called.")
            return result
        return wrapper
    
    @my_decorator
    def say_hello(name):
        print(f"Hello, {name}!")
    
    say_hello("Alice")

    运行上述代码,输出结果为:

    Something is happening before the function is called.

    Hello, Alice!

    Something is happening after the function is called.

    2.2 类装饰器的定义和使用

    类装饰器与函数装饰器类似,只不过它们接受一个类作为参数,并返回一个新类。

    最简单的类装饰器可以这样定义:

    def class_decorator(cls):
        class WrappedClass(cls):
            def new_method(self):
                print("This is a new method added by the decorator.")
            def existing_method(self)ktXkmwjaC:
                print("This method is overridden by the decorator.")
        return WrappedClass
    
    @class_decorator
    class MyClass:
        def existing_method(self):
            print("This method exists in the original class.")
    
    obj = MyClass()
    obj.new_method()          # 调用新增的方法
    obj.existing_method()     # 调用被重写的方法

    运行上述代码,输出结果为:

    This is a new method added by the decorator.

    This method is overridden by the decorator.

    在这个例子中,class_decorator 是一个类装饰器,它接受一个类 MyClass 作为参数,并返回一个新的类 WrappedClassWrappedClass 继承自 MyClass,并新增和重写了一些方法。

    3. 类装饰器的应用场景

    类装饰器在实际开发中有很多应用场景,下面是几个常见的例子:

    3.1. 自动添加属性

    类装饰器可以用来自动为类添加一些属性。

    例如,我们可以创建一个装饰器,自动为类添加一个 created_at 属性,记录对象的创建时间。

    import datetime
    
    def add_timestamp(cls):
        class WrappedClass(cls):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.created_at = datetime.datetime.now()
        return WrappedClass
    
    @add_timestamp
    class MyClass:
        def __init__(self, name):
            self.name = name
    
    obj = MyClass("Alice")
    print(obj.name)        # 输出: Alice
    print(obj.created_at)  # 输出: 对象的创建时间

    3.2 访问控制

    类装饰器可以用来控制类的方法访问权限。

    例如,我们可以创建一个装饰器,要求调用某些方法时必须有管理员权限javascript。

    def require_admin(cls):
        class WrappedClass(cls):
            def admin_method(self, *args, **kwargs):
                if not self.is_admin:
                    raise PermissionError("Admin privileges required")
                return super().admin_method(*args, **kwargs)
        return WrappedClass
    
    @require_admin
    class MyClass:
     android   def __init__(self, is_admin):
            self.is_admin = is_admin
    
        def admin_method(self):
            print("This is an admin method.")
    
    admin_obj = MyClass(is_admin=True)
    admin_obj.admin_method()  # 正常调用
    
    user_obj = MyClass(is_admin=False)
    user_obj.admin_method()   # 抛出 PermissionError

    3.3 数据验证

    类装饰器可以用来在类方法调用前进行数据验证。

    例如,我们可以创建一个装饰器,验证方法参数的类型。

    def validate_params(cls):
        class WrappedClass(cls):
            def method_with_validation(self, x):
                if not isinstance(x, int):
                    raise ValueError("Parameter x must be an integer")
                return super().method_with_validation(x)
        return WrappedClass
    
    @validate_params
    class MyClass:
        def method_with_validation(self, x):
            print(f"Received {x}")
    
    obj = MyClass()
    obj.method_with_validation(10)  # 正常调用
    obj.method_with_validation("a") # 抛出 ValueError

    4. 综合示例

    接下来,我们将通过一个综合示例来展示如何使用类装饰器。

    这个示例将包含一个日志记录装饰器、一个权限检查装饰器和一个数据验证装饰器。

    import datetime
    
    def log_activity(cls):
        class WrappedClass(cls):
            def __getattribute__(self, name):
                attr = super().__getattribute__(name)
                if callable(attr):
                    def logged(*args, **kwargs):
                        print(f"Calling {name} with arguments {args} and {kwargs} at {datetime.datetime.now()}")
                        result = attr(*args, **kwargs)
                        print(f"{name} returned {result}")
                        return result
                    return logged
                return attr
        return WrappedClass
    
    def require_permission(permission):
        def decorator(cls):
            class WrappedClass(cls):
                def __getattribute__(self, name):
                    attr = super().__getattribute__(name)
                    if callable(attr):
                        def secured(*args, **kwargs):
                            if not self.has_permission(permission):
                                raise PermissionError(f"Permission {permission} required")
                            return attr(*args, **kwargs)
                        return secured
                    return attr
            return WrappedClass
        return decorator
    
    def validate_params(cls):
        class WrappedClass(cls):
            def method_with_validation(s编程客栈elf, x):
                if not isinstance(x, int):
                    raise ValueError("Parameter x must be an integer")
                return super().method_with_validation(x)
        return WrappedClass
    
    @log_activity
    @require_permission("admin")
    @validate_params
    class MyClass:
        def __init__(self, is_admin):
         android   self.is_admin = is_admin
    
        def has_permission(self, permission):
            return self.is_admin
    
        def method_with_validation(self, x):
            return f"Received {x}"
    
    # 测试综合示例
    admin_obj = MyClass(is_admin=True)
    print(admin_obj.method_with_validation(10))  # 正常调用
    
    try:
        admin_obj.method_with_validation("a")  # 抛出 ValueError
    except ValueError as e:
        print(e)
    
    user_obj = MyClass(is_admin=False)
    try:
        user_obj.method_with_validation(10)  # 抛出 PermissionError
    except PermissionError as e:
        print(e)

    4.1 输出结果

    Calling __init__ with arguments (True,) and {} at 2024-07-11 14:23:45.123456

    __init__ returned None

    Calling method_with_validation with arguments (10,) and {} at 2024-07-11 14:23:45.123456

    method_with_validation returned Received 10

    Received 10

    Calling method_with_validation with arguments ('a',) and {} at 2024-07-11 14:23:45.123456

    Parameter x must be an integer

    Calling __init__ with arguments (False,) and {} at 2024-07-11 14:23:45.123456

    __init__ returned None

    Calling method_with_validation with arguments (10,) and {} at 2024-07-11 14:23:45.123456

    Permission admin required

    4.2 解释

    1. 日志记录装饰器:记录类的方法调用,包括输入参数和返回值。
    2. 权限检查装饰器:检查用户是否具有调用方法的权限。
    3. 数据验证装饰器:验证方法参数的类型。

    通过这种方式,我们可以在不修改类本身的情况下,为类添加额外的功能。

    总结

    类装饰器是 Python 中一个非常强大的工具,可以用来扩展和修改类的行为。通过类装饰器,我们可以在不修改原始代码的情况下为类添加额外的功能。

    在实际开发中,类装饰器有很多应用场景,包括日志记录、访问控制、数据验证等。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜