装饰器 篇

装饰器

在Python中,装饰器(Decorator)是一个高级功能,它允许你在不修改函数或类本身代码的情况下,给函数或类动态地添加额外的功能。装饰器本质上是一个接受函数作为参数的高阶函数,并返回一个新的函数。

装饰器的语法使用 @ 符号,后面跟着装饰器的名称,然后是一个函数定义。装饰器通常用于添加日志、性能分析、事务处理、缓存、权限校验等功能。

下面是一个简单的装饰器示例,用于计算函数的执行时间:

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {func.__name__} took {end_time - start_time} seconds to execute.")
        return result
    return wrapper

@timer_decorator
def my_function():
    time.sleep(1)  # 假设这是一个耗时的操作
    print("Function executed!")

my_function()

在这个例子中,timer_decorator 是一个装饰器函数,它接受一个函数作为参数(在这个例子中是 my_function),然后定义了一个新的函数 wrapper。wrapper 函数记录了 my_function 的执行时间,并在执行完成后打印出来。最后,timer_decorator 返回 wrapper 函数,这个返回的函数替代了原来的 my_function。

使用 @timer_decorator 语法,我们告诉Python在定义 my_function 之后立即应用 timer_decorator。这样,当我们调用 my_function 时,实际上是在调用 wrapper 函数。

装饰器可以更加复杂,并且可以接受参数,以提供更大的灵活性。它们也可以用于类方法,以装饰类的方法。

需要注意的是,装饰器不应该修改被装饰函数的源代码或调用方式,它们应该保持函数或方法的签名不变,只是简单地添加额外的行为。

classmethod()

classmethod 是Python内置的一个装饰器,用于指示一个方法应当作为类方法而不是实例方法。类方法属于类本身,而不是类的任何特定实例。这意味着类方法可以通过类名直接调用,也可以通过类的实例调用,但不管如何调用,类方法的第一个参数总是类本身,通常命名为 cls。

类方法通常用于执行与类相关但不依赖于类实例的任务,例如创建类的实例、修改类属性或访问与类关联的静态资源。

下面详细讲解 classmethod 装饰器:
定义类方法

使用 @classmethod 装饰器来定义类方法。例如:

class MyClass:
    @classmethod
    def my_class_method(cls, arg1, arg2):
        print(f"Calling class method of {cls.__name__} with arguments {arg1} and {arg2}")

# 调用类方法
MyClass.my_class_method("hello", "world")  # 使用类名调用

# 或者
obj = MyClass()
obj.my_class_method("hello", "world")  # 使用实例调用

在这个例子中,my_class_method 是一个类方法。无论我们是使用 MyClass 类名还是它的一个实例 obj 来调用这个方法,cls 参数总是接收 MyClass 类本身。
类方法的用途

类方法通常用于以下几种情况:

工厂方法:创建并返回类的实例。
class MyClass:
    @classmethod
    def from_string(cls, string_representation):
        # 解析 string_representation 并创建类的实例
        return cls(parsed_data)
修改类属性:类方法可以修改类级别的状态。
class MyClass:
    count = 0

    @classmethod
    def increment_count(cls):
        cls.count += 1
访问类级别的资源:类方法可以访问与类关联的静态资源或配置。
class MyClassFactory:
    CLASSES = {"A": MyClassA, "B": MyClassB}

    @classmethod
    def get_class(cls, class_name):
        return cls.CLASSES.get(class_name)

类方法与实例方法的比较

  • 实例方法:第一个参数是 self,代表类的实例。实例方法必须通过类的实例来调用,并且 self 参数会自动绑定到调用该方法的实例上。
class MyClass:
    def my_instance_method(self, arg):
        print(f"Calling instance method of {self.__class__.__name__} with argument {arg}")
  • 类方法:第一个参数是 cls,代表类本身。类方法可以通过类名或类的实例来调用,cls 参数会自动绑定到类上。

总的来说,classmethod 装饰器使得你能够定义一种特殊类型的方法,即类方法,它们与实例方法不同,因为它们与类本身而不是类的实例相关联。

property()

在Python中,property()是一个内置函数,用于将一个方法变成属性getter。当你访问这个属性时,实际上是在调用这个方法。此外,property()还可以接受setter和deleter方法,从而允许你对属性进行赋值和删除操作。

使用property()可以使得类更加面向对象,它允许你像访问数据属性一样来访问方法,同时你还可以控制对这个“属性”的读取、赋值和删除操作。

下面是property()的基本用法:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        """Getter for radius."""
        return self._radius

    @radius.setter
    def radius(self, value):
        """Setter for radius."""
        if value < 0:
            raise ValueError("Radius cannot be negative!")
        self._radius = value

    @radius.deleter
    def radius(self):
        """Deleter for radius."""
        del self._radius

# 使用property的示例
c = Circle(5)
print(c.radius)  # 调用getter,输出: 5

c.radius = 10  # 调用setter
print(c.radius)  # 再次调用getter,输出: 10

del c.radius  # 调用deleter
# 如果再次访问c.radius,将会抛出一个AttributeError,因为_radius已经被删除了

在上面的例子中,radius是一个属性,但实际上它背后有三个方法:

  • radius(self): 这是一个getter方法,用于读取_radius的值。
  • radius(self, value): 这是一个setter方法,用于设置_radius的值,并且在设置之前进行了一些验证(例如,确保半径不是负数)。
  • radius(self): 这是一个deleter方法,用于删除_radius。

通过property()装饰器,你可以将这三个方法合并成一个单一的属性,从而提供更简洁、更面向对象的接口。

注意,如果你只定义了一个getter方法,而没有定义setter或deleter方法,那么该属性就是只读的。如果你定义了setter方法,那么该属性就是可写的。如果你定义了deleter方法,那么该属性就可以被删除。

使用property()的一个主要好处是,你可以在getter、setter和deleter方法中添加额外的逻辑,例如验证、计算或通知其他属性等,而用户在使用这个属性时完全不需要知道这些背后的复杂性。

staticmethod()

staticmethod 是Python中的一个装饰器,用于指示一个方法应当作为静态方法而不是实例方法或类方法12。

静态方法的特点是:

不需要传递实例参数和类参数:静态方法既不需要传递 self(实例参数)也不需要传递 cls(类参数)12。
无法访问实例属性和方法:由于静态方法不与任何实例或类关联,因此它不能访问实例的属性或方法,也不能访问类的属性或方法(除非这些属性或方法是作为全局变量或函数参数传递的)12。
通过类名调用:静态方法可以通过类名直接调用,而不需要创建类的实例12。

静态方法通常用于实现与类相关但不依赖于类实例或类状态的函数,例如工具函数或辅助函数2。

下面是一个使用 staticmethod 的例子:

class MyClass:
    @staticmethod
    def my_static_method(arg1, arg2):
        print(f"Calling static method with arguments {arg1} and {arg2}")

# 调用静态方法
MyClass.my_static_method("hello", "world")

# 由于静态方法不依赖于实例,因此不能通过实例调用(但技术上仍然可以这样做)
obj = MyClass()
obj.my_static_method("hello", "world")  # 这将正常工作,但不是一个好的做法

在这个例子中,my_static_method 是一个静态方法,它不接受 self 或 cls 参数,并且可以通过 MyClass 类名直接调用。尽管可以通过类的实例调用静态方法,但这通常不是一个好的做法,因为它违反了静态方法的初衷。

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊猫Devin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值