On 5/6/05, Guido van Rossum <[EMAIL PROTECTED]> wrote: > [Michele] > > Honestly, I don't care, since "eval" happens only once at decoration time. > > There is no "eval" overhead at calling time, so I do not expect to have > > problems. I am waiting for volunteers to perform profiling and > > performance analysis ;) > > Watch out. I didn't see the code referred to, but realize that eval is > *very* expensive on some other implementations of Python (Jython and > IronPython). Eval should only be used if there is actual user-provided > input that you don't know yet when your module is compiled; not to get > around some limitation in the language there are usually ways around > that, and occasionally we add one, e.g. getattr()).
I actually posted the code on c.l.p. one month ago asking if there was a way to avoid "eval", but I had no answer. So, let me repost the code here and see if somebody comes out with a good solution. It is only ~30 lines long (+ ~30 of comments & docstrings) ## I suggest you uncomment the 'print lambda_src' statement in _decorate ## to understand what is going on. import inspect def _signature_gen(func, rm_defaults=False): argnames, varargs, varkwargs, defaults = inspect.getargspec(func) argdefs = defaults or () n_args = func.func_code.co_argcount n_default_args = len(argdefs) n_non_default_args = n_args - n_default_args non_default_names = argnames[:n_non_default_args] default_names = argnames[n_non_default_args:] for name in non_default_names: yield "%s" % name for i, name in enumerate(default_names): if rm_defaults: yield name else: yield "%s = arg[%s]" % (name, i) if varargs: yield "*%s" % varargs if varkwargs: yield "**%s" % varkwargs def _decorate(func, caller): signature = ", ".join(_signature_gen(func)) variables = ", ".join(_signature_gen(func, rm_defaults=True)) lambda_src = "lambda %s: call(func, %s)" % (signature, variables) # print lambda_src # for debugging evaldict = dict(func=func, call=caller, arg=func.func_defaults or ()) dec_func = eval(lambda_src, evaldict) dec_func.__name__ = func.__name__ dec_func.__doc__ = func.__doc__ dec_func.__dict__ = func.__dict__ # copy if you want to avoid sharing return dec_func class decorator(object): """General purpose decorator factory: takes a caller function as input and returns a decorator. A caller function is any function like this: def caller(func, *args, **kw): # do something return func(*args, **kw) Here is an example of usage: >>> @decorator ... def chatty(f, *args, **kw): ... print "Calling %r" % f.__name__ ... return f(*args, **kw) >>> @chatty ... def f(): pass >>> f() Calling 'f' """ def __init__(self, caller): self.caller = caller def __call__(self, func): return _decorate(func, self.caller) Michele Simionato _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com