Python:将所有函数包装在一个库中 [英] Python: wrap all functions in a library

查看:36
本文介绍了Python:将所有函数包装在一个库中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用另一个内部团队提供的库.(摇摇欲坠的比喻现在开始)

We use a library provided by another internal team. (Shaky analogy starts now)

from externalTeam import dataCreator
datacreator.createPizza()
datacreator.createBurger()
datacreator.createHotDog()

最近我们发现他们的一种方法在某些情况下需要超过一分钟才能执行.为了调试这个,我不得不进入我们的代码并在每次调用这个方法时添加超时.

Recently we found a single method of theirs was taking over a minute to execute in certain situations. To debug this, I had to go into our code and add timeouts around every call of this method.

import time
from externalTeam import dataCreator
start = time.clock()
datacreator.createPizza()
stop = time.clock()
print "It took %s seconds to perform createPizza" % (str(stop-start))

事后看来,那是因为我们到处都在调用 createPizza,而我们不控制 createPizza 本身(这个类比在这里开始有点不合时宜).我宁愿只在一个地方调用 createPizza,并且能够围绕它添加一个计时器.我的第一个想法是在我自己的包装类中创建一个包装所有方法.不过,这与 DRY 正好相反,无论何时他们添加另一种方法,我都必须更新我们的库以将其包装起来:

In hindsight, that's because we're calling createPizza all over the place, and we don't control createPizza itself (the analogy is starting to break down a little here). I'd rather just call createPizza in one place, and be able to add a timer around that. My first thought to accomplish this would be to create a wrap all their methods in my own wrapper class. That's the opposite of DRY though, and anytime they add another method I'd have to update our library to wrap that as well:

import time
from externalTeam import dataCreator
def createPizza(self):
    start = time.clock()
    datacreator.createPizza()
    stop = time.clock()
    print "It took %s seconds to perform createPizza" % (str(stop-start))

def createBurger(self):
    start = time.clock()
    datacreator.createPizza()
    stop = time.clock()
    print "It took %s seconds to perform createBurger" % (str(stop-start))

def createHotDog(self):
    start = time.clock()
    datacreator.createPizza()
    stop = time.clock()
    print "It took %s seconds to perform createHotDog" % (str(stop-start))    

我想要的是一种始终围绕从 dataCreator 调用的每个函数执行几行代码的方法.必须有某种方法可以通过一个中间类来做到这一点,该类的方法可以动态定义 - 或者更确切地说是未定义,对吗?

What I want is a way to always execute a few lines of code around every function that's being called from dataCreator. There must be some way to do that through an intermediate class whose methods can be dynamically defined - or rather left undefined, right?

推荐答案

我将创建一个 dataCreator 适配器类,其工作方式如下:

I would create a dataCreator adapter class that would work like this:

  1. 有一个 methods2wrap 列表,其中包含 dataCreator 中需要包装到调试/计时功能中的方法.
  2. 有一个重写的 __getattribute__() 将 1:1 映射到 dataCreator 方法上,将 methods2wrap 中的方法包装到定时调试中消息.
  1. Have a methods2wrap list of the methods from dataCreator that needs to be wrapped into the debugging/timing functionality.
  2. Have an overridden __getattribute__() that would map 1:1 onto the dataCreator methods, wrapping the methods in methods2wrap into a timing debug message.

概念验证代码(示例包装类 list 并在其方法 append 周围插入调试时间戳).

Proof-of-concept code (the example wrap the class list and insert a debugging timestamp around its method append).

import time

class wrapper(list):

    def __getattribute__(self, name):
        TO_OVERRIDE = ['append']
        if name in TO_OVERRIDE:
            start = time.clock()
        ret = super(list, self).__getattribute__(name)
        if name in TO_OVERRIDE:
            stop = time.clock()
            print "It took %s seconds to perform %s" % (str(stop-start), name)
        return ret

profiled_list = wrapper('abc')
print profiled_list
profiled_list.append('d')
print profiled_list
profiled_list.pop()
print profiled_list

当然,您可以在此示例的基础上构建并使其具有参数化,以便在初始化时您可以设置要包装的类以及应计时的方法...

Of course you could build on this example and make it parametric, so that at initialisation time you can set what class to wrap and what methods should be timed...

注意 TO_OVERRIDE 在每次 __getattribute__ 调用时被重新分配.这是设计使然.如果您将其作为类属性,__getattribute__ 将递归循环(您应该使用对父 __getattribute__ 方法的显式调用来检索它,但这可能是比简单地从头开始重建列表要慢.

Note that TO_OVERRIDE is reassigned at each __getattribute__ call. This is by design. If you you would make it as a class attribute, __getattribute__ would recursively loop (you should use an explicit call to the parent __getattribute__ method to retrieve it, but this would probably be slower than simply rebuild the list from scratch.

HTH

这篇关于Python:将所有函数包装在一个库中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆