Думайте в декораторе как о функции, которая возвращает другую функцию. То, что вы хотите сделать, это добавить поведение к функции без изменения его реализации.
На практике этот декоратор имеет следующее поведение.
def title_decorator(print_name_function):
# now your decorator have a local variable (print_name_function)
# in that function scope that variable is a reference to another
# function
def wrapper():
# now you write a function that do something
print("Professor:")
print_name_function() # here you function is calling a scope
# variable that by the way is another
# function. See that the scope of this
# variable is *title_decorator*
# now instead to return your argument function you return another
# with some other behavior
return wrapper
OBS: Когда wrapper вызывает функцию, это ссылка на объект. Имейте это в виду