首页 > 解决方案 > Using decorators with class

问题描述

I am trying to add a decorator to required class methods and I have come up with the following code for it. I need this to work with all the similar classes.

import allure

def class_method_dec(cls):
    """
    Decorator function to decorate required class methods.
    """
    if cls.method1:
        cls.method1= allure.step(cls.method1)

    if cls.method2:
        cls.method2= allure.step(cls.method2)

    if cls.method3:
        cls.method3= allure.step(cls.method3)

    return cls


@class_method_dec
class TestClass:

    def __init__(self, a, b):
        self.a = a
        self.b = b

    def method1(self):
        """
        method docstring
        """
        pass

    def method2(self):
        """
        method docstring
        """
        pass

    def method3(self):
        """
        method docstring
        """
        pass

Is this the right way to do it? I am looking for the best way to do this.

Also, I understand that we can use functools.wraps to preserve the docstring when decorating functions. Is there a need of something like it when we are decorating classes?

标签: pythonpython-decorators

解决方案


从 Satwik Kansal 出色的 Python 元编程IBM 教程中,我发现了这个宝石:

Satwik 首先定义了一个装饰器:


from functools import wraps
import random
import time

def wait_random(min_wait=1, max_wait=30):
    def inner_function(func):
        @wraps(func)
        def wrapper(args, **kwargs):
            time.sleep(random.randint(min_wait, max_wait))
            return func(args, **kwargs)

        return wrapper

    return inner_function

然后他创建了一个类包装器,将这个装饰器应用于一个类:

def classwrapper(cls):
    for name, val in vars(cls).items():
        #callable return True if the argument is callable
        #i.e. implements the __call
        if callable(val):
            #instead of val, wrap it with our decorator.
            setattr(cls, name, wait_random()(val))
    return cls

应用:


# decorate a function

@wait_random(10, 15)
def function_to_scrape():
    #some scraping stuff

# decorate a class

@classwrapper
class Scraper:
    # some scraping stuff

要在您的情况下使用它,请 wait_random用您自己的装饰器替换。把你的功能变成装饰器。例如

from functools import wraps
import allure

def apply_allure():
    def inner_function(func):
        @wraps(func)
        def wrapper(args, **kwargs):
            func = allure.step(func)
            return func(args, **kwargs)

        return wrapper

    return inner_function

classwrapper替换wait_randomapply_allure

请阅读教程以获取更多信息和解释


推荐阅读