We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Decorators

Remember function transformations, where a (higher-order) function takes a function and returns a function with new behavior? Python decorators offer a kind of syntactic sugar around that. ("Syntactic sugar" just means "a more convenient syntax.")

Example:

from collections.abc import Callable


def vowel_counter(func_to_decorate: Callable[[str], None]) -> Callable[[str], None]:
    vowel_count: int = 0

    def wrapper(doc: str) -> None:
        nonlocal vowel_count
        vowels: str = "aeiou"
        for char in doc:
            if char.lower() in vowels:
                vowel_count += 1
        print(f"Vowel count: {vowel_count}")
        func_to_decorate(doc)

    return wrapper


@vowel_counter
def process_doc(doc: str) -> None:
    print(f"Document: {doc}")


process_doc("What")
# Vowel count: 1
# Document: What

process_doc("A wonderful")
# Vowel count: 5
# Document: A wonderful

process_doc("world")
# Vowel count: 6
# Document: world

The @vowel_counter line is "decorating" the process_doc function with the vowel_counter function. vowel_counter is called once when process_doc is defined with the @ syntax, but the wrapper function that it returns is called every time process_doc is called. That's why vowel_count is preserved and printed after each time.

It's Just Syntactic Sugar

Python decorators are just another (sometimes simpler) way of writing a higher-order function. These two pieces of code are identical:

With Decorator

@vowel_counter
def process_doc(doc: str) -> None:
    print(f"Document: {doc}")


process_doc("Something wicked this way comes")

Without Decorator

def process_doc(doc: str) -> None:
    print(f"Document: {doc}")


process_doc = vowel_counter(process_doc)
process_doc("Something wicked this way comes")

Assignment

The provided file_type_aggregator function is intended to decorate other functions. It assumes that the function it decorates has exactly 2 positional arguments.

Create a process_doc function that is decorated by file_type_aggregator. It should return the following string:

f"Processing doc: '{doc}'. File Type: {file_type}"

Where doc and file_type are its positional arguments. (See the line where result is assigned to func_to_decorate(doc, file_type).)