python修饰符(装饰器)@property、@classmethod 和 @staticmethod

装饰器的简单介绍

@property 装饰器用于将类的方法转换为属性,使得可以像访问属性一样访问方法。
使得访问方法像访问属性一样,代码更简洁。
可以在保持接口不变的情况下更改实现细节。
可以轻松添加对属性的验证和计算逻辑。

@classmethod 装饰器用于定义类方法。类方法的第一个参数必须是表示类本身的 cls,而不是实例。类方法通常用于创建类的工厂方法。
可以访问和修改类级别的属性。
常用于工厂方法,简化对象创建过程。
提供一种替代构造函数的方法来实例化对象。

@staticmethod 装饰器用于定义静态方法。静态方法不依赖于类或实例,它们类似于普通函数,但在类的命名空间中。静态方法通常用于实现逻辑上与类相关但不需要访问类或实例的功能。
逻辑上属于类,但不需要访问类或实例的状态。
提高代码组织性,将相关函数放在一起。
不需要传递 self 或 cls 参数。

@abstractmethod 装饰器用于定义抽象方法,这些方法必须在子类中实现。这个装饰器通常与 abc 模块中的 ABC 类一起使用。
强制子类实现特定方法,确保接口一致性。
提供一种定义接口的方式,支持多态。

@functools.wraps 装饰器用于编写装饰器时,保留被装饰函数的元数据(如函数名、文档字符串、注解等)。
保留被装饰函数的元数据,便于调试和文档生成。
改善装饰器的可读性和可维护性。

@lru_cache 装饰器用于缓存函数的返回值,以提高性能。它使用最近最少使用(LRU)算法来缓存结果。
提高函数性能,特别是对于计算密集型函数。
自动管理缓存大小,防止内存过度使用。

@dataclass 装饰器用于自动生成类的初始化方法、比较方法等,使得定义数据类更加简单和高效。这个装饰器在 dataclasses 模块中。
自动生成常用方法(如 init、repr、eq 等),减少样板代码。
提供一种简洁的方式来定义数据类。

本文将详细介绍常用的装饰器: @property、@classmethod 、 @staticmethod、@abstractmethod

@property 装饰器

@property 装饰器用于将类的方法转换为属性,使得可以像访问属性一样访问方法。这使得代码更加简洁和直观。

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name
    
    @property
    def age(self):
        return self._age
    
    @age.setter  # 设置属性的setter方法
    def age(self, value):
        if value < 0:
            raise ValueError("Age cannot be negative")
        self._age = value

#使用示例
p = Person("Alice", 30)
print(p.name)  # 输出: Alice
print(p.age)   # 输出: 30

p.age = 35  # 通过setter方法设置年龄
print(p.age)  # 输出: 35
# p.age = -5  # 会抛出 ValueError

@property 优势:

  • 使得访问方法像访问属性一样,代码更简洁。
  • 可以在保持接口不变的情况下更改实现细节。
  • 可以轻松添加对属性的验证和计算逻辑。

@classmethod 装饰器

@classmethod 装饰器用于定义类方法。类方法的第一个参数必须是表示类本身的 cls,而不是实例。类方法通常用于创建类的工厂方法。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def from_birth_year(cls, name, birth_year):
        return cls(name, 2023 - birth_year)

# 使用示例

p1 = Person("Alice", 30)
p2 = Person.from_birth_year("Bob", 1990)

print(p1.name, p1.age)  # 输出: Alice 30
print(p2.name, p2.age)  # 输出: Bob 33

@classmethod 优势:

  • 可以访问和修改类级别的属性。

  • 常用于工厂方法,简化对象创建过程。

  • 提供一种替代构造函数的方法来实例化对象。

@staticmethod 装饰器

@staticmethod 装饰器用于定义静态方法。静态方法不依赖于类或实例,它们类似于普通函数,但在类的命名空间中。静态方法通常用于实现逻辑上与类相关但不需要访问类或实例的功能。

class Math:
    @staticmethod
    def add(x, y):
        return x + y

@staticmethod
    def subtract(x, y):
        return x - y

# 使用示例

print(Math.add(5, 3))  # 输出: 8
print(Math.subtract(5, 3))  # 输出: 2

@staticmethod 优势:

  • 逻辑上属于类,但不需要访问类或实例的状态。
  • 提高代码组织性,将相关函数放在一起。
  • 不需要传递 self 或 cls 参数。

@abstractmethod 装饰器

@abstractmethod 装饰器用于定义抽象方法,这些方法必须在子类中实现。这个装饰器通常与 abc 模块中的 ABC 类一起使用。

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        return "Woof"

class Cat(Animal):
    def make_sound(self):
        return "Meow"

# 使用示例

dog = Dog()
cat = Cat()
print(dog.make_sound())  # 输出: Woof
print(cat.make_sound())  # 输出: Meow
#animal = Animal()  # 不能实例化抽象类,会抛出 TypeError

@abstractmethod 优势:

  • 强制子类实现特定方法,确保接口一致性。

  • 提供一种定义接口的方式,支持多态。

自定义装饰器

Python 允许我们创建自定义装饰器。装饰器本质上是一个函数,它接受另一个函数作为参数,并返回一个新的函数。自定义装饰器可以用于日志记录、计时、访问控制、缓存等多种用途。下面是两个示例,演示如何创建和使用自定义装饰器。

自定义日志装饰器

import functools

def log_calls(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with args={args} and kwargs={kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned {result}")
        return result
    return wrapper

# 使用示例
@log_calls
def add(x, y):
    return x + y

@log_calls
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(add(3, 5))  # 调用 add(3, 5)
print(greet("Alice"))  # 调用 greet("Alice")
print(greet("Bob", greeting="Hi"))  # 调用 greet("Bob", greeting="Hi")

自定义计时装饰器

import functools
import time

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        elapsed_time = end_time - start_time
        print(f"{func.__name__} executed in {elapsed_time:.4f} seconds")
        return result
    return wrapper

# 使用示例
@timer
def slow_function(duration):
    time.sleep(duration)
    return "Done"

print(slow_function(2))  # 调用 slow_function(2)
posted @ 2024-07-25 09:35  Van-kai  阅读(147)  评论(0)    收藏  举报