更改装饰器以在新模块

时间:2017-10-31 16:54:04

标签: python python-2.7 decorator

我有一个字段为spent_times的课程。 spent_times是一个列表,此类的所有方法都会写一些信息,这对于日志记录很有用。

另外,我有一个装饰器,它计算每个函数的执行时间并将其写入spent_times

这是我的装饰者的实现:

def timing(message):
    def wrap(function):
        def called(*args, **kwargs):
            time_start = timer()
            spent_time = round(timer() - time_start, 5)

            if not args:
                return function(*args, **kwargs), spent_time

            obj = args[0]
            if hasattr(obj, "spent_times"):
                obj.spent_times.append("{}={:.5f}".format(message, spent_time))
                return function(*args, **kwargs)
            else:
                logging.warning('Decorator allows to set spent_time attribute!')
        return called
    return wrap 

正如你在装饰器中看到的那样,如果调用函数具有属性 self ,则会进行检查。

如果有,我可以在现场列表spent_times中编写所需信息,如果没有,则装饰器返回执行和功能本身所花费的时间。

我在一个单独的模块中使用这个装饰器,第二种情况(当没有找到 self 时)属于这个模块中的一些其他函数,它们不属于类,其中定义了spend_time列表,但我执行了里面我的班级,所以我能够实现以下结构:

这是“外部”功能的声明

def calc_users(requests, priority):
     # .....

在我的课程中,我执行它并以这种方式更新我的spend_time列表:

 response, spent_time = calc_users(requests, priority)
 self.class_obj.spent_times.append("user_calculation={:.5f}".format(spent_time))

这不是很好,但它至少起作用了。

现在,我在不同的新模块中移动了我的类的一些函数,我想使用相同的装饰器时序。

有人可以帮助我在新模块中实现这种时序实现。我不知道,我现在可以做些什么来更新我的spent_times列表。

这两个模块将同时工作,我不能创建类的对象并将其作为参数传递给新模块,因为(据我所知)将有两个对象,并且将不会正确更新spent_times 。

也许有办法以某种方式传递对spent_times的引用,但我不想在新模块中更改我的函数的参数,因为我认为在这种情况下共享责任的原则将被打破(装饰器)负责记录,为其行动起作用。)

那么如何改进装饰器或如何将spent_times列表传递给新模块?

任何帮助都将非常感谢!

P.S。

也许让spent_times成为一个全局变量? (在最糟糕的情况下)

1 个答案:

答案 0 :(得分:1)

全局列表似乎很好,但您也可以通过在实例化后删除类来使用类并创建单例。这可以防止创建另一个实例:

# mymodule.py

from timeit import default_timer as timer

class Timing(object):
    def __init__(self):
        self.spent_times = []

    def __call__(self, message):
        def wrap(function):
            def called(*args, **kwargs):
                time_start = timer()
                spent_time = round(timer() - time_start, 5)
                self.spent_times.append("{}={:.5f}".format(message, spent_time))
                return function(*args, **kwargs)
            return called
        return wrap 

timing = Timing()
del Timing # prevent another instance

现在导入另一个模块:

from mymodule import timing

@timing('Hello')
def add(a, b):
    return a + b

特殊方法__call__使类的实例表现得像一个函数,即它可以用()调用。 您可以使用self.attr而不是全局变量的优势。

实例化后删除类会阻止创建另一个实例。这被称为单身人士。现在,无论您使用timing作为装饰器的频率如何,所有时间都会在同一个列表中结束。