From: MRAB on
LX wrote:
> 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.

pass_decorator will be called when the decorated function is _defined_,
but not when the decorated function is _called_.
From: Steven D'Aprano on
On Wed, 31 Mar 2010 22:27:05 +0100, MRAB wrote:

> LX wrote:
[...]
>> It looks to me the call stack still includes the additional level of
>> the decorator... what am I missing? Thank you for your time.
>
> Are you still defining your decorators in the same way as in your
> original post?
>
> A decorator shouldn't call the function it's decorating.

*raises eyebrow*

Surely, in the general case, a decorator SHOULD call the function it is
decorating? I'm sure you know that, but your wording is funny and could
confuse the OP.

In this specific case, where the OP wants a "do nothing pass-decorator",
he should do this:

def decorator(func):
if __debug__:
...
else:
return func

rather than this:

def decorator(func):
if __debug__:
...
else:
def inner(*args):
return func(*args)
return inner



--
Steven
From: MRAB on
Steven D'Aprano wrote:
> On Wed, 31 Mar 2010 22:27:05 +0100, MRAB wrote:
>
>> LX wrote:
> [...]
>>> It looks to me the call stack still includes the additional level of
>>> the decorator... what am I missing? Thank you for your time.
>> Are you still defining your decorators in the same way as in your
>> original post?
>>
>> A decorator shouldn't call the function it's decorating.
>
> *raises eyebrow*
>
> Surely, in the general case, a decorator SHOULD call the function it is
> decorating? I'm sure you know that, but your wording is funny and could
> confuse the OP.
>
What I mean is that the function that's doing the decorating shouldn't
call the function; it's the locally-defined wrapper function that calls
the decorated function.

For example, in my version of trace_decorator() it's show() that calls
the decorated function, not trace_decorator() itself.

Unless the word 'decorator' refers to the locally-defined function, in
which case, what do you call the function that does the wrapping, the
one whose name follows the '@'?

> In this specific case, where the OP wants a "do nothing pass-decorator",
> he should do this:
>
> def decorator(func):
> if __debug__:
> ...
> else:
> return func
>
> rather than this:
>
> def decorator(func):
> if __debug__:
> ...
> else:
> def inner(*args):
> return func(*args)
> return inner
>
>
>

From: Steven D'Aprano on
On Thu, 01 Apr 2010 00:27:51 +0100, MRAB wrote:

>>> A decorator shouldn't call the function it's decorating.
>>
>> *raises eyebrow*
>>
>> Surely, in the general case, a decorator SHOULD call the function it is
>> decorating? I'm sure you know that, but your wording is funny and could
>> confuse the OP.
>>
> What I mean is that the function that's doing the decorating shouldn't
> call the function; it's the locally-defined wrapper function that calls
> the decorated function.

Ah, gotcha, that makes sense. Now I understand the distinction you were
making. Thank you for the clarification.



--
Steven
From: MRAB on
Steven D'Aprano wrote:
> On Thu, 01 Apr 2010 00:27:51 +0100, MRAB wrote:
>
>>>> A decorator shouldn't call the function it's decorating.
>>> *raises eyebrow*
>>>
>>> Surely, in the general case, a decorator SHOULD call the function it is
>>> decorating? I'm sure you know that, but your wording is funny and could
>>> confuse the OP.
>>>
>> What I mean is that the function that's doing the decorating shouldn't
>> call the function; it's the locally-defined wrapper function that calls
>> the decorated function.
>
> Ah, gotcha, that makes sense. Now I understand the distinction you were
> making. Thank you for the clarification.
>
I had the following idea: define the terms 'decorator', 'decoration' and
'decoratee'. The decorator applies the decoration to the decoratee. The
decoratee is the function defined locally in the decorator.
First  |  Prev  |  Next  |  Last
Pages: 1 2 3
Prev: "Usability, the Soul of Python"
Next: PyScripter Logo