Decorators not worth the effort
Jean-Michel Pichavant
jeanmichel at sequans.com
Fri Sep 14 05:28:22 EDT 2012
----- Original Message -----
> On Sep 14, 3:54 am, Jean-Michel Pichavant <jeanmic... at 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
More information about the Python-list
mailing list