1

This simple decorator works as expected:

def protect(*permissions):
    def outer(f):
        def inner(*args):
            print permissions[0]
            return f(*args)  
        return inner  
    return outer

@protect('protected')
def func(var):
    return var

print func('something')

The output is:

protected
something

Moving beyond a Python shell and using the decorator in the larger scope of my project, something strange is happening: while inside of the inner function, permissions is not defined.

I'm thinking there must be some Python variable scoping/decorator subtleties I'm unaware of that could be causing this. Any insights are appreciated.

2
  • 2
    Well, we'll need the code that doesn't work ;) It's output (or rather, the exact error message) would help as well. Commented Feb 23, 2011 at 20:38
  • It was a NameError when I tried to access the value of permissions. I'm scratching my head now b/c everything is working. Must have been a problem beyond the decorator. Sorry for the bad question. Commented Feb 23, 2011 at 21:19

2 Answers 2

1

In my mind I could figure out what is going on - let me try to spell it out:

it has to do with Python not "perceiving" the "permissions" variable as existing on the scopes outside the "inner" function - since when "inner" itself is defined, "permissions" would long have been defined in the 'outsidemost' scope of protect. Thus, when compiling inner the variale is taken as being a global variable. (That is why the exact error message is needed - NameErrors can be for local variables used before definition, or for non-existing global variables - the exact message will tell much in this case)

In other words, you most likley have hit an implementation bug - please try to expose the minimum ammount of code that causes the issue and the exact python version you are using. If possible try with the latest micro version available for you - and ten it will be time to open an issue at bugs.python.org

I see two workarounds -- the first one would be a hack that would confirm my diagnosis - and might not work at all: Make a reading access to the permissions variable on the outer function, outside inner's body: that should make the interpretor "perceive" it as a non-local variable in outer, and propagate it into inner.

The other workaround is more solid and consistent - and maybe even better code-styling for yu in this case: to use a class as the decorator in this case, instead of relying on multiple nested functions and its closures.

The above snippet could be rewritten as:

class Protect(object):
    def __init__(self, *permissions):
        self.permissions = permissions
    def __call__(self, f):
        def inner(*args):
            print self.permissions[0]
            return f(*args)  
        return inner  

@Protect('protected')
def func(var):
    return var

print func('something')

This code does not rely on nested closures, thus avoidnign the bug you've hit. Besides, it follows the "flat is better than nested" and "explict is better than implicit" coding guidelines.

But please, help everyone to trace this bug, by giving us your version and code that actually triggers this behavior, if not opening an issue at python.org

Sign up to request clarification or add additional context in comments.

1 Comment

ooops ii t is "working now" then?? No python bug them - either way, think on uing this flattened version of the decorator - it is easier to track errors on it.
0

I ran into this problem once, it was because you cannot set a variable that you put in a closure. Don't know if it's the case for you, but it's good to know.

1 Comment

Don't think that applies here because I'm not trying to set it. Just accessing it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.