views:

109

answers:

5

Why does this not work? How can I make it work? That is, how can I make gu accessible inside my decorated function?

def decorate(f):
    def new_f():
        def gu():
            pass
        f()
    return new_f

@decorate
def fu():
    gu()

fu()

Do I need to add gu to a dictionary of defined functions somehow? Or can I add gu to the local namespace of f before calling it?

+1  A: 

gu is local to the new_f function, which is local to the decorate function.

Geo
+1  A: 

gu() is only defined within new_f(). Unless you return it or anchor it to new_f() or something else, it cannot be referenced from outside new_f()

I don't know what you're up to, but this scheme seems very complex. Maybe you can find a less complicated solution.

Ber
The example is pointless but I'm trying to give the simplest example to illustrate the problem. It should be fairly clear what I want to do. I want to define a function in a decorator definition for use in the decorated function.
Alex
@Alex: Could you provide a description of the higher level problem you are trying to solve? Maybe then someone can suggest a cleaner solution using an entirely different approach.
Ber
+2  A: 

If you need to pass gu to fu you need to do this explicitly by parameters:

def decorate(f):
    def new_f():
        def gu():
            pass
        f(gu)
    return new_f

@decorate
def fu(gu):
    gu()

fu()
lispmachine
Is there no way I can add the function gu to an attribute of f to minimize the disruption to the actual definition of fu. I mean, this is the goal of decorators, or AOP; to separate out concerns.
Alex
@Alex if `gu` is separate concept from `fu` why does you call it in `fu` instead of `new_f`? If they are really separate it's even more convenient when they are not visible from each other. Could you put some more detail into your question to clarify?
lispmachine
A: 

In principle you can create a new function using the same code as the old one but substituting the global scope with an amended one:

import new

def with_bar(func):
    def bar(x):
        return x + 1
    f_globals = func.func_globals.copy()
    f_globals['bar'] = bar
    return new.function(func.func_code, f_globals,
                        func.func_name, func.func_defaults, func.func_closure)

@with_bar
def foo(x):
    return bar(x)

print foo(5) # prints 6

In practice you really should find a better way to do this. Passing in functions as parameters is one option. There might be other approaches too, but it's hard to tell what would fit without a high-level problem description.

Ants Aasma
A: 

Why not make your decorator a class rather than a function? It's apparently possible, as I discovered when I looked through the help for the property builtin. (Previously, I had thought that you could merely apply decorators to classes, and not that the decorators themselves could be classes.)

(Of course, gu would have to be a method of the class or of an inner class.)

JAB