In article <CALwzidk11rqXjaxcwNKy5C2iotaBO_BcDWL_zFC6Rctue=4...@mail.gmail.com>, Ian Kelly <ian.g.ke...@gmail.com> wrote:
> On Thu, Nov 10, 2011 at 2:52 PM, Russell E. Owen <ro...@uw.edu> wrote: > > I am trying to write a decorator that times an instance method and > > writes the results to a class member variable. For example: > > > > def timeMethod(func): > > def wrapper(self, *args, **keyArgs): > > t1 = time.time() > > res = func(self, *args, **keyArgs) > > duration = time.time() - t1 > > self.timings[func.__name__] = duration > > return res > > return wrapper > > > > This works, but I'm not very happy with the way self.timings is obtained. > > What do you feel is wrong with it? Oops, I stripped so much out of my example that I stripped the ugly bit. This is closer to the original and demonstrated the issue: def timeMethod(func): name = func.__name__ + "Duration" def wrapper(self, *args, **keyArgs): t1 = time.time() res = func(self, *args, **keyArgs) duration = time.time() - t1 self.timings[name] = duration return res return wrapper I don't like the way name is passed into wrapper. It works, but it looks like magic. A class offers an obvious place to save the information. Or I could just generate the name each time. I realize I'm showing the limits of my understanding of python binding of variable names, but I also think that if I find it confusing then others will, as well. > sum(os.times()[:2]) instead, which (assuming your script is > single-threaded) will more accurately count the actual CPU time spent > in the function rather than real time, which could be quite different > if the CPU is busy. Thanks for the suggestion. I decided to use time.clock(), which I understand gives basically the same information (at a resolution that is sufficient for my needs). > Also, why do you need this? If you're just trying to evaluate the > speed of your code, you should consider using a proper profiler or the > timeit module. The former will tell you how much time is spent in > each function, while the latter runs the code a large number of times > in a loop, which gives you better precision for quick methods. It is for timing stages of a data processing pipeline. Only long-running tasks will be timed. Repeatedly running to get better times is neither practical nor necessary to get a good feeling of where the time is being spent. > > I first tried to write this as a class (for readability), and this did > > NOT work: > > > > class timeMethod(object): > > def __init__(self, func): > > self.func = func > > def __call__(self, *args, **keyArgs): > > t1 = time.time() > > res = self.func(*args, **keyArgs) > > duration = time.time() - t1 > > args[0].timings.set(self.func.__name__, duration) > > return res > > > > In the first case the wrapper is called as an unbound function, so it > > works. But in the second case the wrapper is called as a bound method -- > > thus args[0] is not func's class instance, and I can't get to the > > timings attribute. > > I prefer the function version myself, but to make this work you could > add something like this (untested) to make your wrapper class a > descriptor that tacks on the self argument: > > def __get__(self, instance, owner): > from functools import partial > if instance is None: > return self > return partial(self, instance) Thank you very much. I'll stick to the function, since it works, but it's nice to know how to work around the problem.
-- http://mail.python.org/mailman/listinfo/python-list