Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!gegeweb.42!gegeweb.eu!gegeweb.org!aioe.org!news.stack.nl!newsfeed.xs4all.nl!newsfeed5.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.001 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'example:': 0.03; 'instance,': 0.05; 'function,': 0.07; 'wrapper': 0.07; 'argument:': 0.09; 'attribute.': 0.09; 'decorator': 0.09; 'descriptor': 0.09; 'func': 0.09; 'myself,': 0.09; 'none:': 0.09; 'def': 0.14; 'cc:addr:python-list': 0.15; '(assuming': 0.16; '*args,': 0.16; 'args[0]': 0.16; 'functools': 0.16; 'instance)': 0.16; 'res': 0.16; 'subject:function': 0.16; 'unbound': 0.16; 'variable.': 0.16; '\xa0def': 0.16; 'subject:question': 0.17; 'wrote:': 0.18; 'instance': 0.18; 'trying': 0.21; 'cc:no real name:2**0': 0.21; 'this?': 0.21; 'runs': 0.23; 'thus': 0.23; 'loop,': 0.23; 'skip:\xa0 40': 0.23; 'works.': 0.23; 'header:In- Reply-To:1': 0.23; 'cc:2**0': 0.25; 'code': 0.25; "i'm": 0.26; 'function': 0.27; 'code,': 0.27; 'import': 0.28; 'script': 0.28; 'tried': 0.28; 'bound': 0.28; 'module.': 0.28; 'work:': 0.28; 'cc:addr:python.org': 0.29; 'message-id:@mail.gmail.com': 0.29; 'second': 0.29; 'class': 0.29; 'precision': 0.30; 'nov': 0.31; 'pm,': 0.31; 'received:209.85.161.46': 0.31; 'received:mail- fx0-f46.google.com': 0.31; 'version': 0.31; 'thu,': 0.32; 'actual': 0.32; "can't": 0.32; 'quite': 0.32; 'it?': 0.33; 'spent': 0.34; 'probably': 0.34; '8bit%:3': 0.34; 'latter': 0.34; '(for': 0.35; 'received:209.85.161': 0.35; 'rather': 0.35; 'something': 0.36; 'instead,': 0.36; 'partial': 0.36; 'but': 0.37; 'using': 0.37; 'could': 0.38; 'received:google.com': 0.38; 'received:209.85': 0.38; 'called': 0.38; 'should': 0.39; 'why': 0.39; 'case': 0.39; 'subject:: ': 0.39; 'skip:_ 10': 0.40; 'received:209': 0.40; 'did': 0.40; 'more': 0.60; 'your': 0.61; 'results': 0.61; '2011': 0.62; 'busy.': 0.67; 'subject:but': 0.67; 'works,': 0.68; 'evaluate': 0.71; 'owen': 0.84; 'subject:class': 0.84; 'timings': 0.84; 'russell': 0.91 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type:content-transfer-encoding; bh=L5ItKqADWhFgm2OWvtC3CtOxEewFMjcqxKXf2Ecfug8=; b=IJ30k8hkO4F5Zm+2kbbMBDPUhLcLi84CB4JvAc/Xp83K4OMJgaJZJ3XPolkiHzPgah 28JJW3FiNeMQyYPsPaufcMsY8G+MPqCf4L/6fveTRwTk6gKLFzS/Zf2tGFWHyj7kBUeH uFv7lQcLvkq6TLemNGhkjaRI4QPthwEiK8MKY= MIME-Version: 1.0 In-Reply-To: References: From: Ian Kelly Date: Thu, 10 Nov 2011 15:35:14 -0700 Subject: Re: Decorator question: prefer class, but only function works To: "Russell E. Owen" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Cc: python-list@python.org X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 57 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1320964546 news.xs4all.nl 6975 [2001:888:2000:d::a6]:35371 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:15565 On Thu, Nov 10, 2011 at 2:52 PM, Russell E. Owen 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): > =A0 =A0def wrapper(self, *args, **keyArgs): > =A0 =A0 =A0 =A0t1 =3D time.time() > =A0 =A0 =A0 =A0res =3D func(self, *args, **keyArgs) > =A0 =A0 =A0 =A0duration =3D time.time() - t1 > =A0 =A0 =A0 =A0self.timings[func.__name__] =3D duration > =A0 =A0 =A0 =A0return res > =A0 =A0return wrapper > > This works, but I'm not very happy with the way self.timings is obtained. What do you feel is wrong with it? You probably should use 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. 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. > I first tried to write this as a class (for readability), and this did > NOT work: > > class timeMethod(object): > =A0 =A0def __init__(self, func): > =A0 =A0 =A0 =A0self.func =3D func > =A0 =A0def __call__(self, *args, **keyArgs): > =A0 =A0 =A0 =A0t1 =3D time.time() > =A0 =A0 =A0 =A0res =3D self.func(*args, **keyArgs) > =A0 =A0 =A0 =A0duration =3D time.time() - t1 > =A0 =A0 =A0 =A0args[0].timings.set(self.func.__name__, duration) > =A0 =A0 =A0 =A0return 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) HTH, Ian