python--常见的装饰器

1. 什么是装饰器?

所谓装饰器可以理解为一种特殊的函数,就是把函数包装一下,为函数添加一些附加功能,装饰器就是一个函数,参数为被包装的函数,返回包装后的函数。

2.常见的装饰器

2.1 @classmethod (内置装饰器)
2.2 @staticmethod (内置装饰器)
2.3 @property (内置装饰器)
2.4 @app (框架提供的装饰器)

2.1 @classmethod

类方法
作用:是一种特殊的方法,可以在不创建类实例的情况下调用,用于定义类方法。
定义:

class Testclassmethod:
	@classmethod
	def test(cls,arg1,arg2):
		pass
#要想调用这个类方法的话,就直接Testclassmethod.test()调用

应用场景:
参考链接:解锁 Python 类方法的精髓:@classmethod 的应用技巧!

2.2.1 替代构造函数
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    @classmethod
    def from_birth_year(cls, name, birth_year):
        age = 2024 - birth_year
        return cls(name, age)

person = Person.from_birth_year("Alice", 1990)
print(person.name, person.age)  # 输出:Alice 34

2.2.2 实现工厂模式

工厂模式:是一种设计模式,目的是简化对象的创建过程。不需要自己去处理复杂的细节。

class Car:
    def drive(self):
        pass

class Sedan(Car):
    def drive(self):
        print("Driving a sedan")

class SUV(Car):
    def drive(self):
        print("Driving an SUV")

class Hatchback(Car):
    def drive(self):
        print("Driving a hatchback")

class CarFactory:
    @classmethod
    def create_car(cls, car_type):
        if car_type == 'sedan':
            return Sedan()
        elif car_type == 'suv':
            return SUV()
        elif car_type == 'hatchback':
            return Hatchback()
        else:
            raise ValueError("Invalid car type")

# 使用工厂模式创建汽车对象
if __name__ == "__main__":
    # 获取用户输入的车型
    car_type = input("Enter the car type (sedan, suv, hatchback): ")
    
    # 通过工厂创建汽车
    car = CarFactory.create_car(car_type)
    
    # 调用汽车的 drive 方法
    car.drive()
2.2.3 实现单例模式

单例模式:也是一种设计模式,目的是在整个程序运行期间,只允许一个类有一个实例存在,并且提供一个全局访问点来获取这个实例。

class Logger:
    _instance = None  # 用于存储单例实例

    def __init__(self):
        self.log_messages = []

    def log_message(self, message):
        self.log_messages.append(message)

    def display_logs(self):
        for message in self.log_messages:
            print(message)

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance

# 使用单例模式创建Logger实例
if __name__ == "__main__":
    # 第一次获取Logger实例
    logger1 = Logger.get_instance()
    logger1.log_message("First message.")

    # 第二次获取Logger实例
    logger2 = Logger.get_instance()
    logger2.log_message("Second message.")

    # 验证两个实例是否相同
    print("Are logger1 and logger2 the same instance?", logger1 is logger2)

    # 显示所有日志
    logger1.display_logs()

2.2 @staticmethod

静态方法
静态方法和类方法十分相似,但是在用法上有轻微的区别,
classmethod必须将类对象的引用作为第一个参数,而staticmethod可以不带任何参数。
由于这个差别,所以二者的适用场景不一样。

因为静态方法与类方法本身没有直接关联,所以更像是类中的一个普通函数,静态方法不会自动接受任何特殊参数,因为静态方法不知道类的状态,例如不可以修改类变量。所以常用于执行与类的实例无关的操作。

类方法是与类关联的方法,可接受一个名为cls的参数,约定俗称写cls,其实可以是任何名字,这个参数表示当前类备色,类方法可以访问和修改类状态,即可以访问和修改类变量。

2.2.1 静态方法例子
class MathUtil:
    @staticmethod
    def add_numbers(a, b):
        """静态方法,用于计算两个数字的和"""
        return a + b

# 使用静态方法
if __name__ == "__main__":
    num1 = float(input("Enter the first number: "))
    num2 = float(input("Enter the second number: "))
    result = MathUtil.add_numbers(num1, num2)
    print(f"The sum of {num1} and {num2} is {result}")

2.3 @property

作用:允许将一个方法定义为类的一个属性来使用(rect.area),而不是像通常那样作为一个方法调用(rect.area())
这样的好处是可以在不改变调用方式的情况下,为读取,设置或删除类的属性提供灵活性,同时可以对这些操作进行控制。
下面举个例子,来验证@property的优势、
  • 没有使用property的例子:
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    def get_celsius(self):
        return self._celsius

    def set_celsius(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._celsius = value

temp = Temperature(25)

# 获取温度
print(temp.get_celsius())  # 输出: 25

# 设置温度
try:
    temp.set_celsius(-300)
except ValueError as e:
    print(e)  # 输出: Temperature below -273.15 is not possible.
  • 使用property的例子
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._celsius = value

temp = Temperature(25)

# 获取温度
print(temp.celsius)  # 输出: 25

# 设置温度
try:
    temp.celsius = -300
except ValueError as e:
    print(e)  # 输出: Temperature b

对比分析
代码简洁性:在使用 @property 的版本中,我们可以直接使用 temp.celsius 来获取和设置温度值,而不需要调用方法。
可读性和可维护性:使用 @property 的代码更加直观,更容易理解。
封装性:即使我们使用了 @property,外部代码仍然不能直接访问 _celsius 这个私有变量,从而保证了数据的安全性。
动态性:使用 @property 可以让我们更容易地改变属性的行为,例如增加更多的逻辑或改变数据存储的方式,而无需更改客户端代码。

  • 其他例子:
    展示了如何使用 @property 来定义一个 getter 方法
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @property
    def age(self):
        """Getter for the age attribute."""
        return self._age

    @age.setter
    def age(self, value):
        """Setter for the age attribute with validation."""
        if value < 0:
            raise ValueError("Age cannot be negative.")
        self._age = value

# 创建一个 Person 实例
person = Person("Alice", 30)

# 使用 getter 方法来获取 age 属性的值
print(person.age)  # 输出: 30

# 使用 setter 方法来设置 age 属性的值
person.age = 35
print(person.age)  # 输出: 35

# 尝试设置一个非法的 age 值
try:
    person.age = -5
except ValueError as e:
    print(e)  # 输出: Age cannot be negative.

2.4 @app

FastAPI 是一个现代的、快速(高性能)的 web 框架,用于构建 APIs。它基于 Python 3.7+ 的标准库,并且利用了 starlette 和 pydantic。FastAPI 提供了许多装饰器来帮助你定义路由和处理 HTTP 请求。
FastAPI 中常用的装饰器。

@app.get: 用于定义 GET 请求的路由。
@app.post: 用于定义 POST 请求的路由。
@app.put: 用于定义 PUT 请求的路由。
@app.delete: 用于定义 DELETE 请求的路由。
@app.patch: 用于定义 PATCH 请求的路由。
@app.options: 用于定义 OPTIONS 请求的路由

各位看官,如果看完感觉有一点点收获的话,可以给点打赏哟。失业创作不易(/(ㄒoㄒ)/~~)
在这里插入图片描述在这里插入图片描述

  • 30
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

赵钱孙李的赵

感谢各位衣食父母

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

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

打赏作者

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

抵扣说明:

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

余额充值