TypeError: 'str' object is not callable - Python Decorator Concept

Viewed 139
def upper_case_decorator(in_arg):
    upper_word = in_arg() # please keep () after in_arg because we are passing function name as input
    result = upper_word.upper()
    return result

@upper_case_decorator
def random_var():
    return "asdfg"
var = random_var()
print(var)

I am trying to implement decorator concept in the above python programming. But , when I run the code, I am facing : TypeError: 'str' object is not callable.

I do not know why I am facing this error. Could anyone help me ?

1 Answers

This isn't how you make a function decorator. The decorator needs to return a new function! What you did was call the method immediately. Try this:

def upper_case_decorator(in_arg):
    def wrapper():
        upper_word = in_arg()
        result = upper_word.upper()
        return result
    return wrapper

@upper_case_decorator
def random_var():
    return "asdfg"

var = random_var()
print(var)

Going a bit further, to make the function decorator more flexible, you want to forward the arguments from the wrapper function to the original. This is usually done by passing *args and **kwargs

def upper_case_decorator(in_arg):
    def wrapper(*args, **kwargs):
        upper_word = in_arg(*args, **kwargs)
        result = upper_word.upper()
        return result
    return wrapper

Going further again, you could make the function decorator itself take arguments. In this scenario, you have a function which returns a decorator, and that decorator returns a wrapped function. For example, in this case you could pass in a separate method that describes how you want to transform the response.

def format_response(response_func):
    def format_response_decorator(original_func):
        def format_response_wrapper(*args, **kwargs):
            return response_func(original_func(*args, **kwargs))
        return format_response_wrapper
    return format_response_decorator


@format_response(lambda s: s + "def")
@format_response(lambda s: "abc" + s)
@format_response(lambda s: s.upper())
def random_var():
    return "test"


print(random_var())
abcTESTdef
Related