Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder1.news.weretis.net!feeder.erje.net!newsfeed.xs4all.nl!newsfeed5.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!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.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'else:': 0.03; 'exception': 0.03; 'argument': 0.04; 'context': 0.05; 'debug': 0.05; 'debugging': 0.05; 'defaults': 0.05; 'method.': 0.05; 'none:': 0.05; 'decorator': 0.07; 'raises': 0.07; 'sphinx': 0.07; 'python': 0.09; '"%s"': 0.09; '**kwargs)': 0.09; '**kwargs):': 0.09; 'arg': 0.09; 'sep': 0.09; 'timeout': 0.09; 'timeout)': 0.09; 'def': 0.10; 'subject:not': 0.11; 'index': 0.13; 'language': 0.14; 'passing': 0.15; '(just': 0.16; 'doc,': 0.16; 'mine.': 0.16; 'run.': 0.16; 'skip:} 10': 0.16; 'developers,': 0.16; 'users.': 0.16; 'wrote:': 0.17; 'exists': 0.17; 'specify': 0.17; 'version.': 0.17; 'code,': 0.18; 'appropriate': 0.20; 'code.': 0.20; 'decorators': 0.22; 'effort.': 0.22; 'pos': 0.22; 'skip:_ 20': 0.22; 'cheers,': 0.23; 'cc:2**0': 0.23; 'example': 0.23; 'specified': 0.23; 'raise': 0.24; 'idea': 0.24; 'non': 0.24; 'header:In-Reply-To:1': 0.25; 'wrote': 0.26; 'cc:addr:gmail.com': 0.27; 'replace': 0.27; 'environment': 0.29; 'factor': 0.29; 'piece': 0.29; 'ret': 0.29; 'sensible': 0.29; 'url:mailman': 0.29; 'skip:_ 10': 0.29; 'class': 0.29; "i'm": 0.29; 'that.': 0.30; 'keyword': 0.30; 'function': 0.30; 'feedback': 0.30; 'expect': 0.31; '(and': 0.32; 'url:python': 0.32; '-----': 0.32; 'switch': 0.32; 'url:listinfo': 0.32; 'platform,': 0.33; 'to:addr:python-list': 0.33; 'everyone': 0.33; 'know.': 0.33; 'skip:d 20': 0.34; 'version': 0.34; 'add': 0.36; 'explain': 0.36; 'but': 0.36; 'url:org': 0.36; 'too': 0.36; 'one,': 0.37; 'does': 0.37; 'why': 0.37; 'passed': 0.37; 'subject:: ': 0.38; 'some': 0.38; 'to:addr:python.org': 0.39; 'where': 0.40; 'skip:" 10': 0.40; 'end': 0.40; 'url:mail': 0.40; 'think': 0.40; 'amazing': 0.61; 'received:194': 0.61; 'spending': 0.61; 'capable': 0.63; 'worth': 0.63; 'more': 0.63; 'hours': 0.66; 'cognitive': 0.84; 'decorate': 0.84; 'flame': 0.84; 'troubles': 0.84; 'factors': 0.95; 'colleagues': 0.97 X-IronPort-AV: E=Sophos;i="4.80,422,1344204000"; d="scan'208";a="725058" X-Virus-Scanned: amavisd-new at zimbra.sequans.com Date: Fri, 14 Sep 2012 11:28:22 +0200 (CEST) From: Jean-Michel Pichavant To: python-list@python.org In-Reply-To: Subject: Re: Decorators not worth the effort MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Mailer: Zimbra 7.2.0_GA_2669 (ZimbraWebClient - GC7 (Linux)/7.2.0_GA_2669) Cc: alex23 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 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: 106 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1347614888 news.xs4all.nl 6840 [2001:888:2000:d::a6]:53854 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:29145 ----- Original Message ----- > On Sep 14, 3:54=C2=A0am, Jean-Michel Pichavant > wrote: > > I don't like decorators, I think they're not worth the mental > > effort. >=20 > Because passing a function to a function is a huge cognitive burden? > -- > http://mail.python.org/mailman/listinfo/python-list >=20 I was expecting that. Decorators are very popular so I kinda already know t= hat the fault is mine. Now to the reason why I have troubles writing them, = I don't know. Every time I did use decorators, I spent way too much time wr= iting it (and debugging it). I wrote the following one, used to decorate any function that access an equ= ipment, it raises an exception when the timeout expires. The timeout is ada= pted to the platform, ASIC of FPGA so people don't need to specify everytim= e one timeout per platform. In the end it would replace=20 def boot(self, timeout=3D15): if FPGA: self.sendCmd("bootMe", timeout=3Dtimeout*3) else: self.sendCmd("bootMe", timeout=3Dtimeout) with @timeout(15) def boot(self, timeout=3DNone): self.sendCmd("bootMe", timeout) I wrote a nice documentation with sphinx to explain this, how to use it, ho= w it can improve code. After spending hours on the decorator + doc, feedbac= k from my colleagues : What the F... !!=20 Decorators are very python specific (probably exists in any dynamic languag= e though, I don't know), in some environment where people need to switch fr= om C to python everyday, decorators add python magic that not everyone is f= amiliar with. For example everyone in the team is able to understand and de= bug the undecorated version of the above boot method. I'm the only one capa= ble of reading the decorated version. And don't flame my colleagues, they'r= e amazing people (just in case they're reading this :p) who are not python = developers, more of users. Hence my original "decorators are not worth the mental effort". Context spe= cific I must admit. Cheers, JM PS : Here's the decorator, just to give you an idea about how it looks. Sma= ll piece of code, but took me more than 2 hours to write it. I removed some= sensible parts so I don't expect it to run. class timeout(object): """Substitute the timeout keyword argument with the appropriate val= ue""" =09FACTORS =3D { =09=09IcebergConfig().platform.ASIC : 1, =09=09IcebergConfig().platform.FPGA : 3, =09=09=09} =09def __init__(self, asic, fpga=3DNone, palladium=3DNone): =09=09self.default =3D asic =09=09self.fpga =3D fpga =09 =09def _getTimeout(self): =09=09platform =3D config().platform =09=09factor =3D self.FACTORS[platform.value] =09=09timeout =3D { =09=09=09=09platform.ASIC : self.default*factor, =09=09=09=09platform.FPGA : self.fpga or self.default*factor, =09=09=09=09}[platform.value] =09=09return timeout =09def __call__(self, func): =09=09def decorated(*args, **kwargs): =09=09=09names, _, _, defaults =3D inspect.getargspec(func) =09=09=09defaults =3D defaults or [] =09=09=09if 'timeout' not in names: =09=09=09=09raise ValueError('A "timeout" keyword argument is required') =09=09=09if 'timeout' not in kwargs: # means the timeout keyword arg is not= in the call =09=09=09=09index =3D names.index('timeout') =09=09=09=09argsLength =3D (len(names) - len(defaults)) =09=09=09=09if index < argsLength: =09=09=09=09=09raise NotImplementedError('This decorator does not support n= on keyword "timeout" argument') =09=09=09=09if index > len(args)-1: # means the timeout has not be passed u= sing a pos argument =09=09=09=09=09timeoutDef =3D defaults[index-argsLength] =09=09=09=09=09if timeoutDef is not None: =09=09=09=09=09=09_log.warning("Decorating a function with a default timeou= t value <> None") =09=09=09=09=09kwargs['timeout'] =3D self._getTimeout() =09=09=09else: =09=09=09=09_log.warning('Timeout value specified during the call, please c= heck "%s" @timeout decorator.' % func.__name__) =09=09=09ret =3D func(*args, **kwargs) =09=09=09return ret =09=09return decorated