Function does not return value when used with decorators

Question:

When I call the function without the decorator a list of all files with the matching extension is returned. However, if I add the decorator @get_time, I do not get a return value from the function.

def get_time(func):
    from time import perf_counter
    from functools import wraps
    """Times any function"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = perf_counter()
        func(*args, **kwargs)
        end_time = perf_counter()
        total_time = round(end_time - start_time, 5)
        print(func.__name__)
        print(f"Took {total_time} seconds")
    return wrapper


def getListOfFiles(dirName, file_extension):
    """
            Finds all files with matching file extension in given directory
            Parameters
            ----------
            dirName : string
                Either a path from a single file or a path of a directory.
            file_extension : string, list of string
                The extension of the file type which should be taken into account.
                Can be one or more than one extension.

            Returns
            -------
            list_of_files : list of string
                Returns list of all files

            """
    import os
    extension_list = []
    if isinstance(file_extension, str):
        extension_list.append(file_extension)
    if isinstance(file_extension, list):
        extension_list = file_extension
    # create a list of file and subdirectories
    # names in the given directory
    listOfFile = os.listdir(dirName)
    allFiles = list()
    # Iterate over all the entries
    for entry in listOfFile:
        # Create full path
        fullPath = os.path.join(dirName, entry)
        # If entry is a directory then get the list of files in this directory
        if os.path.isdir(fullPath):
            allFiles = allFiles + getListOfFiles(fullPath, extension_list)
        else:
            name, extension = os.path.splitext(fullPath)
            if any(extension in s for s in extension_list):
                allFiles.append(fullPath)
    return allFiles

@get_time
def get_list_of_files(path, file_type):
    """
        Generates a list with all file path from a given path.
        Parameters
        ----------
        path : string
            Either a path from a single file or a path of a directory.
        file_type : string, list of string
            The extension of the file type which should be taken into account.
            Can be one or more than one extension.

        Returns
        -------
        list_of_files : list of string
            Returns the synchrony of the input spike trains.

        """
    import os
    all_files = []
    # check if path is a file or directory
    if os.path.isdir(path):
        all_files = getListOfFiles(path, file_type)
    else:
        all_files.append(path)
    return all_files




if __name__ == '__main__':
    path = "/mnt/HDD/Data/FrenchData/culture_du_29_11_2021_version_matlab_experience_1"
    all_files = get_list_of_files(path, [".png"])
    print(all_files)
Asked By: Broxy

||

Answers:

The wrapper inside the decorator needs to return the result from func():

def get_time(func):
    from time import perf_counter
    from functools import wraps
    """Times any function"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = perf_counter()
        result = func(*args, **kwargs)
        end_time = perf_counter()
        total_time = round(end_time - start_time, 5)
        print(func.__name__)
        print(f"Took {total_time} seconds")
        return result
    return wrapper
Answered By: quamrana

You need to store return value of the actual call in wrapper and return it at the end.

@wraps(func)
    def wrapper(*args, **kwargs):
        start_time = perf_counter()
        func(*args, **kwargs) # <- Here you do not do anything with returned value
        end_time = perf_counter()
        total_time = round(end_time - start_time, 5)
        print(func.__name__)
        print(f"Took {total_time} seconds")

Change it to:

@wraps(func)
    def wrapper(*args, **kwargs):
        start_time = perf_counter()
        ret = func(*args, **kwargs) # <- return value is stored for later return
        end_time = perf_counter()
        total_time = round(end_time - start_time, 5)
        print(func.__name__)
        print(f"Took {total_time} seconds")
        return ret
Answered By: matszwecja