----- Original Message -----
> On Sep 14, 3:54 am, Jean-Michel Pichavant <[email protected]>
> 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