Search code examples
pythonstringoopdecorator

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


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 ?


Solution

  • 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