----- Original Message -----
> On Sep 14, 3:54 am, Jean-Michel Pichavant <jeanmic...@sequans.com>
> wrote:
> > I don't like decorators, I think they're not worth the mental
> > effort.
> 
> Because passing a function to a function is a huge cognitive burden?
> --
> http://mail.python.org/mailman/listinfo/python-list
> 

I was expecting that. Decorators are very popular so I kinda already know that 
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 writing it 
(and debugging it).

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... !! 

Decorators are very python specific (probably exists in any dynamic language 
though, I don't know), in some environment where people need to switch from C 
to python everyday, decorators add python magic that not everyone is familiar 
with. For example everyone in the team is able to understand and debug the 
undecorated version of the above boot method. I'm the only one capable of 
reading the decorated version. And don't flame my colleagues, they're 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 
specific I must admit.

Cheers,

JM

PS : Here's the decorator, just to give you an idea about how it looks. Small 
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 value"""
        FACTORS = {
                IcebergConfig().platform.ASIC : 1,
                IcebergConfig().platform.FPGA : 3,
                        }

        def __init__(self, asic, fpga=None, palladium=None):
                self.default = asic
                self.fpga = fpga
        
        def _getTimeout(self):
                platform = config().platform
                factor = self.FACTORS[platform.value]
                timeout = {
                                platform.ASIC : self.default*factor,
                                platform.FPGA : self.fpga or 
self.default*factor,
                                }[platform.value]
                return timeout

        def __call__(self, func):
                def decorated(*args, **kwargs):
                        names, _, _, defaults =  inspect.getargspec(func)
                        defaults = defaults or []
                        if 'timeout' not in names:
                                raise ValueError('A "timeout" keyword argument 
is required')
                        if 'timeout' not in kwargs: # means the timeout keyword 
arg is not in the call
                                index = names.index('timeout')
                                argsLength = (len(names) - len(defaults))
                                if index < argsLength:
                                        raise NotImplementedError('This 
decorator does not support non keyword "timeout" argument')
                                if index > len(args)-1: # means the timeout has 
not be passed using a pos argument
                                        timeoutDef = defaults[index-argsLength]
                                        if timeoutDef is not None:
                                                _log.warning("Decorating a 
function with a default timeout value <> None")
                                        kwargs['timeout'] = self._getTimeout()
                        else:
                                _log.warning('Timeout value specified during 
the call, please check "%s" @timeout decorator.' % func.__name__)
                        ret = func(*args, **kwargs)
                        return ret
                return decorated
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to