Skip to main content
 首页 » 编程设计

python之类 Python 中的装饰器

2025年05月04日20youxin

对不起我的英语。我想创建一个可以检查每个步骤方法并将其写入数据库的装饰器方法。

这是我的方法:

class Test: 
 
    @StepStatusManager.logger_steps("GET_LIST") # TypeError: logger_steps() missing 1 required positional argument: 'type' 
    def get_mails(self): 
       print("GET_MAIL")     

这是我的装饰类:

class StepStatusManager: 
 
    def __init__(self): 
        self.db = DB() 
 
    def logger_steps(self, type): 
        def logger_steps(func): 
            @functools.wraps(func) 
            def wrapper(*args): 
                try: 
                    func(*args) 
                    self.db.setStatus(type) 
                except BaseException as e: 
                    print(e) 
 
            return wrapper 
 
        return logger_steps 

请您参考如下方法:

您正在尝试直接从类 StepStatusManager 调用实例方法 logger_steps,Python 正在获取值 "GET_LIST"作为 self 参数而不是 type。您应该创建 StepStatusManager 的实例,然后让装饰器改为调用实例的方法。它可以很简单:

manager = StepStatusManager() 
 
class Test: 
    @manager.logger_steps("GET_LIST") 
    def get_mails(self): 
       print("GET_MAIL") 

这现在是创建类的一个实例,然后在实例上调用方法,而不是尝试直接从类中调用方法。您现在可以使用 manager 来装饰任意数量的方法。此外,这将使所有修饰的方法都使用相同的 StepStatusManager,但如果您愿意,可以创建不同的实例并使用它们来修饰不同的方法;如果需要,这将允许您对不同的方法使用不同的 self.db。

另一种方法是在类中使用 db 变量,并使 logger_steps 成为 class method相反:

class StepStatusManager: 
 
    db = DB() 
 
    @classmethod 
    def logger_steps(cls, type): 
        def logger_steps(func): 
            @functools.wraps(func) 
            def wrapper(*args): 
                try: 
                    func(*args) 
                    cls.db.setStatus(type) 
                except BaseException as e: 
                    print(e) 
 
            return wrapper 
 
        return logger_steps 
 
class Test: 
    @StepStatusManager.logger_steps("GET_LIST") 
    def get_mails(self): 
       print("GET_MAIL") 

但是请注意,这不太灵活,因为它不允许您使用不同的管理器装饰方法,如果您需要的话。此外,这主要等同于拥有一个 StepStatusManager 模块,而不是一个类,其中 db 是一个模块变量,logger_steps 是一个模块功能,如果你想要这个功能,那可能会更清楚:

# StepStatusManager.py 
 
# ... 
 
db = DB() 
 
def logger_steps(type): 
    def logger_steps(func): 
        @functools.wraps(func) 
        def wrapper(*args): 
            try: 
                func(*args) 
                cls.db.setStatus(type) 
            except BaseException as e: 
                print(e) 
 
        return wrapper 
 
    return logger_steps 
 
# test.py 
 
import StepStatusManager 
 
class Test: 
    @StepStatusManager.logger_steps("GET_LIST") 
    def get_mails(self): 
       print("GET_MAIL") 

同样,这可能比您第一个提出的基于类的解决方案更直接但更不灵活。


编辑:

为了完整性和比较,这里还有另一个版本,类似于 @classmethod 的版本, 但使用 @staticmethod相反(要了解这两个装饰器之间的细微差别,请检查关于它的许多 SO 问题之一,例如 What is the difference between @staticmethod and @classmethod? 或 Meaning of @classmethod and @staticmethod for beginner? ):

class StepStatusManager: 
 
    db = DB() 
 
    @staticmethod 
    def logger_steps(type): 
        def logger_steps(func): 
            @functools.wraps(func) 
            def wrapper(*args): 
                try: 
                    func(*args) 
                    StepStatusManager.db.setStatus(type) 
                except BaseException as e: 
                    print(e) 
 
            return wrapper 
 
        return logger_steps 
 
class Test: 
    @StepStatusManager.logger_steps("GET_LIST") 
    def get_mails(self): 
       print("GET_MAIL") 

由于 @classmethod 和 @staticmethod 经常发生这种情况,因此差异非常小。如果您使用继承,或者如果您使用元类、装饰器或类似的东西,它们的行为可能会有所不同,但除此之外它们几乎相同。