Python: wrap all functions in a library

こ雲淡風輕ζ 提交于 2019-12-04 08:19:24

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

  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.

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...

EDIT: 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

If you're trying to profile Python code, you should use Python's built-in profiling libraries instead of trying to do it manually.

Why not a single wrapper function which just calls its argument?

def wrapper(func, *args, **kwargs):
    ... timing logic ...
    response = func(*args, **kwargs)
    ... more timing logic
    return response

and call it:

wrapper(datacreator.createPizza, arg1, arg2, kwarg1=kwarg)

note you pass the function itself, but without calling it.

The following template could help:

class MeteredClient(Client):
  def __init__(self, *args, **kwargs):
    super(MeteredClient, self).__init__(*args, **kwargs)

  def __getattribute__(self, method_name):
    attribute = super(Client, self).__getattribute__(method_name)

    if not inspect.ismethod(attribute):
      return attribute

    metric = TIMINGS.labels(method_name)

    def decorator(*args, **kw):
      start_time = get_time()
      rv = attribute(*args, **kw)
      metric.observe(get_time() - start_time)
      return rv

    return decorator
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!