Stefan
Stefan

Reputation: 2194

Python Decorator with Arguments only called once

Please consider the following simplified example:

permitted = True
class is_allowed(object):
    def __init__(self, some_arg):
        # this is actually needed in the complete code
        self.some_arg = some_arg

    def __call__(self, f):
        if permitted == False:
            raise Exception("not authenticated to do that")
        def wrapped_f(*args, **kwargs):
            f(*args, **kwargs)
        return wrapped_f

@is_allowed("blah")
def print_hi():
    print("hi")

print_hi()
permitted = False
print_hi()

I guess the problem is that the decorator is only called once when the function print_hi() is defined. Because of that the change of the global variable has no effect. Is there any way to circumwent this behaviour?

Upvotes: 4

Views: 1403

Answers (1)

Ryan Haining
Ryan Haining

Reputation: 36802

Move the check inside of the wrapped_f

def __call__(self, f):
    def wrapped_f(*args, **kwargs):
        if not permitted:
            raise Exception("not authenticated to do that")
        f(*args, **kwargs)
    return wrapped_f

Outside of the wrapped_f, it is checked at the creation of the function. Inside, it becomes part of the body of the new callable, which means it will be checked each time there is a call.

You want to realize that wrapped_f will be called instead of print_hi, so you want any behavior that should be included in the function to go inside of that.

Upvotes: 6

Related Questions