Python中内置的常用装饰器
装饰器的详细介绍和定义参看这篇:
python中的装饰器_python 定义装饰器-CSDN博客
这篇博客主要是简单介绍装饰器作用,并列举常用的几个装饰器。(面试被问到了(;′⌒`))
python中的装饰器Decorator 是python中的一个高级特性,它允许不修改函数代码的前提下,动态地给函数增加功能。
装饰器的本质是一个函数或类,它接受一个函数的输入,并返回一个新函数,这个函数通常是对原函数的扩展或者修改。
装饰器的作用和优势:
1. 代码复用:将某些通用功能(日志、缓存)封装为装饰器,多个函数可以复用。2. 增强函数功能
3. 符合开放-关闭原则: 对扩展开放,对修改封闭。
常用装饰器
@property 属性装饰器
作用:把一个方法变成属性调用,允许通过属性方式访问计算结果。
属性是什么?
“属性”是面向对象编程(OOP)中的一个重要概念。简单来说,属性就是对象所拥有的数据或状态,用来描述对象的特征。
- 属性(Attribute) 是对象的一个数据成员,用于存储对象的状态信息。
- 属性一般以变量的形式存在于类的实例中。
- 属性用来描述对象的特征或状态,比如人的姓名、年龄,圆的半径、颜色等。
class Circle:def __init__(self, radius):self._radius = radius@propertydef area(self):return 3.14159 * self._radius ** 2c = Circle(5)
print(c.area)
如果不用装饰器:
class Circle:def __init__(self, radius):self._radius = radiusdef area(self):return 3.14159 * self._radius ** 2c = Circle(5)
print(c.area()) # 注意这里需要调用方法
@staticmethod 静态方法装饰器
不需要实例和类作为参数,类似普通函数。不需要接收实例(self
)或类(cls
)作为第一个参数。
换句话说,静态方法就像是放在类命名空间中的普通函数,它既不像实例方法那样隐式传入实例引用,也不像类方法那样隐式传入类引用。
作用是什么?
一个静态方法和定义在类外的普通函数,从技术上调用方式类似,但静态方法被放到类的命名空间内,有两个优点:
- 命名空间组织:让函数的含义和类相关联。
- 代码可读性增强:调用时通过类名点调用,能表达逻辑关联。
使用场景:
工具函数:实现与类逻辑相关,但不依赖实例或类状态的辅助功能。比如格式化数据、计算公式等。
组织代码结构:把函数放在类中,体现逻辑上的归属关系,而非放在全局命名空间。
class MyClass:@staticmethoddef static_method():print("这是静态方法")MyClass.static_method()
不使用@staticmethod,直接在类中定义一个普通函数会报错:
class Utils:def add(x, y):return x + y# 类调用 print(Utils.add(1, 2)) # 输出: 3# 实例调用 u = Utils() # print(u.add(3, 4)) # 这样会报错:TypeError: add() takes 2 positional arguments but 3 were given
- 直接用
Utils.add(1,2)
没问题;- 但用实例
u.add(3,4)
时,Python会自动把u
作为第一个参数传入,即add(u, 3, 4)
,导致参数数量不对,报错。使用@staticmethod:
class Utils:@staticmethoddef add(x, y):return x + y# 类调用 print(Utils.add(1, 2)) # 输出: 3# 实例调用 u = Utils() print(u.add(3, 4)) # 输出: 7
@classmethod 类方法装饰器
用于将类中的方法定义为类方法,类方法的第一个参数必须是类本身(通常命名为 cls
),而不是实例(self
)。
class MyClass:@classmethoddef my_class_method(cls, arg1, arg2):print(f"cls: {cls}")print(f"arg1: {arg1}, arg2: {arg2}")
# 方法1
MyClass.my_class_method(1, 2)
# 方法2
obj = MyClass()
obj.my_class_method(3, 4)
两种调用方式,无论怎么调用,Python 都会自动将实际调用者的类作为第一个参数 cls
传入。
应用场景:
- 工厂方法:类方法常用作工厂函数,返回当前类的不同实例。
- 访问或修改类属性:类方法可用于访问或修改类级别的属性,对所有实例生效。
- 子类化友好:类方法可以自动识别是哪一个子类调用,从而实例化正确的类型。
未使用@classmethod vs 使用
情况一
未使用:
class Animal:def __init__(self, name, age):self.name = nameself.age = age# 静态方法版本@staticmethoddef from_birth_year(name, birth_year):current_year = 2024age = current_year - birth_year# 只能硬编码类名,无法兼容继承return Animal(name, age)class Dog(Animal):passdog = Dog.from_birth_year("Buddy", 2015) print(type(dog)) # <class '__main__.Animal'> ←返回的是父类Animal,不是Dog
使用:
class Animal:def __init__(self, name, age):self.name = nameself.age = age@classmethoddef from_birth_year(cls, name, birth_year):current_year = 2024age = current_year - birth_year# 用cls来创建实例,兼容继承return cls(name, age)class Dog(Animal):passdog = Dog.from_birth_year("Buddy", 2015) print(type(dog)) # <class '__main__.Dog'> ←返回的是Dog实例
情况二
未使用:class Counter:count = 0def increase(self):# 如果这里写 self.count += 1,其实是修改实例属性,而不是类属性self.count += 1c1 = Counter() c2 = Counter() c1.increase() c2.increase() print(Counter.count) # 输出: 0 print(c1.count) # 输出: 1 print(c2.count) # 输出: 1
- 实例方法修改的其实是实例自己的属性,不会影响整个类。
使用:
class Counter:count = 0@classmethoddef increase(cls):cls.count += 1Counter.increase() Counter.increase() print(Counter.count) # 输出: 2
- 通过
cls.count
直接修改类属性,影响所有实例。
装饰器是什么时候执行的?类定义还是实例化?
答:在类定义的时候就被执行,修改函数对象,实例化对象的时候装饰器已经生效了。