类Python内的装饰器

时间:2018-10-10 10:50:14

标签: python decorator

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

这是我的方法:

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

1 个答案:

答案 0 :(得分:5)

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

StepStatusManager

这现在正在创建类的实例,然后在该实例上调用方法,而不是尝试直接从类中调用方法。现在,您可以使用manager = StepStatusManager() class Test: @manager.logger_steps("GET_LIST") def get_mails(self): print("GET_MAIL") 装饰任意数量的方法。同样,这将使所有装饰的方法都使用相同的manager,但是如果您愿意,可以创建不同的实例,并使用它们来装饰不同的方法;如果需要,您可以将不同的StepStatusManager用于不同的方法。

另一种方法可能是在类中使用self.db变量,而将db设为class method

logger_steps

但是请注意,这不太灵活,因为如果需要,它将不允许您使用由不同的管理器修饰的方法。另外,这几乎等效于拥有一个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

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


编辑:

仅出于完整性和比较的考虑,这是另一个版本,类似于使用@classmethod的版本,但改用@staticmethod(要了解这两个装饰器之间的细微差别,请检查其中一个所以对此有疑问,例如What is the difference between @staticmethod and @classmethod?Meaning of @classmethod and @staticmethod for beginner?):

# 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")

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经常发生这种情况,因此差别很小。如果您使用继承,或者使用元类,装饰器或类似的东西,它们的行为可能会有所不同,但是除此之外,它们几乎是相同的。