Prev: "Usability, the Soul of Python"
Next: PyScripter Logo
From: LX on 29 Mar 2010 20:54 Hi all, I have a question about decorators. I would like to use them for argument checking, and pre/post conditions. However, I don't want the additional overhead when I run in non-debug mode. I could do something like this, using a simple trace example. @decorator def pass_decorator(f, *args, **kw): # what about the slow-down that incurs when using pass_decorator? return f(*args, **kw) @decorator def trace_decorator(f, *args, **kw): print "calling %s with args %s, %s" % (f.func_name, args, kw) return f(*args, **kw) trace_enable_flag = False #__debug__ trace = trace_decorator if trace_enable_flag else pass_decorator Trouble is, there is still an additional encapsulating function call. Is there any way to eliminate the extra function call altogether? Thanks in advance!
From: MRAB on 29 Mar 2010 21:34 LX wrote: > Hi all, I have a question about decorators. I would like to use them > for argument checking, and pre/post conditions. However, I don't want > the additional overhead when I run in non-debug mode. I could do > something like this, using a simple trace example. > > > @decorator > def pass_decorator(f, *args, **kw): # what about the slow-down that > incurs when using pass_decorator? > return f(*args, **kw) > > @decorator > def trace_decorator(f, *args, **kw): > print "calling %s with args %s, %s" % (f.func_name, args, kw) > return f(*args, **kw) > > trace_enable_flag = False #__debug__ > trace = trace_decorator if trace_enable_flag else pass_decorator > > > Trouble is, there is still an additional encapsulating function call. > Is there any way to eliminate the extra function call altogether? > Thanks in advance! I think you have misunderstood certain details about decorators. This code with a decorator: @decorator def hello(): print "hello world" basically does this: def hello(): print "hello world" hello = decorator(hello) so your non-decorator just needs to return the function it was passed: def pass_decorator(func): return func and your trace decorator would be something like this: def trace_decorator(func): def show(*args, **kwargs): print "calling %s with args %s, %s" % (func.func_name, args, kwargs) result = func(*args, **kwargs) print "returning %s from %s" % (result, func.func_name) return result return show
From: Steven D'Aprano on 29 Mar 2010 22:11 On Mon, 29 Mar 2010 17:54:26 -0700, LX wrote: > Hi all, I have a question about decorators. I would like to use them for > argument checking, and pre/post conditions. However, I don't want the > additional overhead when I run in non-debug mode. I could do something > like this, using a simple trace example. def decorator(func): if __debug__: @functools.wraps(func) def inner(*args, **kwargs): preprocess() result = func(*args, **kwargs) postprocess() return result return inner else: return func -- Steven
From: LX on 30 Mar 2010 16:43 On Mar 29, 6:34 pm, MRAB <pyt...(a)mrabarnett.plus.com> wrote: > LX wrote: > > Hi all, I have a question about decorators. I would like to use them > > for argument checking, and pre/post conditions. However, I don't want > > the additional overhead when I run in non-debug mode. I could do > > something like this, using a simple trace example. > > > @decorator > > def pass_decorator(f, *args, **kw): # what about the slow-down that > > incurs when using pass_decorator? > > return f(*args, **kw) > > > @decorator > > def trace_decorator(f, *args, **kw): > > print "calling %s with args %s, %s" % (f.func_name, args, kw) > > return f(*args, **kw) > > > trace_enable_flag = False #__debug__ > > trace = trace_decorator if trace_enable_flag else pass_decorator > > > Trouble is, there is still an additional encapsulating function call. > > Is there any way to eliminate the extra function call altogether? > > Thanks in advance! > > I think you have misunderstood certain details about decorators. > > This code with a decorator: > > @decorator > def hello(): > print "hello world" > > basically does this: > > def hello(): > print "hello world" > hello = decorator(hello) > > so your non-decorator just needs to return the function it was passed: > > def pass_decorator(func): > return func > > and your trace decorator would be something like this: > > def trace_decorator(func): > def show(*args, **kwargs): > print "calling %s with args %s, %s" % (func.func_name, > args, kwargs) > result = func(*args, **kwargs) > print "returning %s from %s" % (result, func.func_name) > return result > return show Sure, but during runtime, pass_decorator will still be called, even though it doesn't do anything. I am wondering if I can disable this additional function call at non-debug runtime. In other words, I want the calling stack to contain no decorator at all, not even pass_decorator. I should mention that, in my code, the symbol "decorator" is imported from Michele Simionato's decorator.py file.
From: LX on 30 Mar 2010 16:44
On Mar 29, 7:11 pm, Steven D'Aprano <ste...(a)REMOVE.THIS.cybersource.com.au> wrote: > On Mon, 29 Mar 2010 17:54:26 -0700, LX wrote: > > Hi all, I have a question about decorators. I would like to use them for > > argument checking, and pre/post conditions. However, I don't want the > > additional overhead when I run in non-debug mode. I could do something > > like this, using a simple trace example. > > def decorator(func): > if __debug__: > @functools.wraps(func) > def inner(*args, **kwargs): > preprocess() > result = func(*args, **kwargs) > postprocess() > return result > return inner > else: > return func > > -- > Steven Actually, I am using "decorator" from Michele Simionato's decorator.py file, at http://pypi.python.org/pypi/decorator. |