From: LX on
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
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
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
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
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.
 |  Next  |  Last
Pages: 1 2 3
Prev: "Usability, the Soul of Python"
Next: PyScripter Logo