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

Reply via email to