Decorators not worth the effort

Jean-Michel Pichavant jeanmichel at sequans.com
Fri Sep 14 09:22:26 EDT 2012



----- Original Message -----
> Jean-Michel Pichavant <jeanmichel at sequans.com> wrote:
> 
> > I wrote the following one, used to decorate any function that
> > access
> > an equipment, it raises an exception when the timeout expires. The
> > timeout is adapted to the platform, ASIC of FPGA so people don't
> > need
> > to specify everytime one timeout per platform.
> > 
> > In the end it would replace
> > 
> > def boot(self, timeout=15):
> >     if FPGA:
> >         self.sendCmd("bootMe", timeout=timeout*3)
> >     else:
> >         self.sendCmd("bootMe", timeout=timeout)
> > 
> > with
> > 
> > @timeout(15)
> > def boot(self, timeout=None):
> >     self.sendCmd("bootMe", timeout)
> > 
> > I wrote a nice documentation with sphinx to explain this, how to
> > use
> > it, how it can improve code. After spending hours on the decorator
> > +
> > doc, feedback from my colleagues : What the F... !!
> > 
> 
> I'd agree with your colleagues. How are you going to ensure that all
> relevant functions are decorated and yet no decorated function ever
> calls another decorated one?
> 
> From the code you posted it would seem appropriate that the
> adjustment
> of the timeout parameter happen in the `sendCmd()` method itself and
> nowhere else. Alternatively use named values for different categories
> of
> timeouts and adjust them on startup so instead of a default of
> `timeout=
> 15` you would have a default `timeout=MEDIUM_TIMEOUT` or whatever
> name
> is appropriate.
> 
> --
> Duncan Booth http://kupuguy.blogspot.com
> --
> http://mail.python.org/mailman/listinfo/python-list

All functions set different timeout values, I cannot use a DEFAULT_VALUE.
All functions are design in the same way:

def doSomeAction(self, timeout):
    preprocess()
    self.sendCmd('relatedAction', timeout) # send the command to the device CLI interface
    postprocess()

Ultimately, the goal is to have something like

@timeout(2)
def doAction1

@timeout(4)
def doAction2

@timeout(12)
def doAction3

and so on... (1 second is important, because there's a platform I remove from my example, didn't want to advertise publicly tech used by the company, that runs 1000 times slower)

Additionally, the multiple check I run within the decorator is for consistency check and argument checking. I though it was a good idea because our python engine is used by a dozen of engineers to control equipment, and any misuse of this new decorator would lead to badly configured timeouts with heavy consequences on the test sessions. Sometimes a RTFM is not enough, when you need to make this work, you slip on your Batman costume like Steven suggested, and you save the day (or so I though :) ) by raising nice exceptions about missing keyword argument.

But let's forget about my poor example, I end up describing my life which is pretty pointless.

Here's Steven example:

# Untested!
def timeout(t=15):
    # Decorator factory. Return a decorator to actually do the work.
    if FPGA:
        t *= 3
    def decorator(func):
        @functools.wraps(func)
        def inner(self, timeout):
            self.sendCmd("bootMe", timeout=t)
        return inner
    return decorator

I can assure you, that for some python users, it's is not easy to understand what it does, this function returning a function which returns another (wrapped) function. It requires some effort.

JM



More information about the Python-list mailing list