decorator needs access to variables where it is used.

Antoon Pardon antoon.pardon at vub.be
Thu Oct 10 06:00:23 EDT 2019


On 9/10/19 13:02, Chris Angelico wrote:
> On Wed, Oct 9, 2019 at 9:53 PM Antoon Pardon <antoon.pardon at vub.be> wrote:
>> I have some logging utilities so that when I write library code, I just use the following.
>>
>> from logutil import Logger
>>
>> log = Logger(__name__)
> Are you always absolutely consistent with this? Do you always have it
> as a module-level variable and always called "log", and you never use
> the name "log" for anything else? (Namespaced usage like "math.log" is
> fine, but you never have a function-local "log" or anything.)

I have been up to now, but I will take this under consideration when
thinking
about how to proceed.
>> And from then on I just use log, to do the logging of that module.
>>
>> But now I would like to write a decorator trace, so that a decorated
>> function would log, its arguments and result.
>>
>> Something like:
>>
>> def trace(func):
>>
>>     def wrapper(*args):
>>         log(DEBUG, "=> %s%s" % (func.__name__, args))
>>         result = func(*args)
>>         log(DEBUG, "%s => %s" (func.__name__, result))
>>
>>     return wrapper
>>
>> The problem is that with this decorater, the log function
>> used, will be the log function defined where the decorator
>> is written and I would prefer it to use the log function
>> where it is used, so that it uses the same log function
>> as the function it decorates.
>>
> The decorator has full access to the function object, including a
> reference to that function's module globals.
>
> def trace(func):
>     log = func.__globals__["log"]
>     ... proceed as before
>
> As long as you can depend on "log" always being a module-level
> (global) name, and not (for instance) a closure variable, this should
> work. It's a bit ugly, but it should be fine since it's buried away in
> the decorator.

Nice idea, I can work with that.

Antoon.



More information about the Python-list mailing list