""" As an object, you can assign the function to a variable like any other object. Notice we don't use parentheses: we are not calling the function, we are putting the function "shout" into the variable "scream". """ scream = shout
print scream() # outputs: Yes!
""" More than that, it means you can remove the old name 'shout', and the function will still be accessible from 'scream'. """ del shout try: print shout() except NameError, e: print e # outputs: name 'shout' is not defined
defmy_shiny_new_decorator(a_function_to_decorate): """ Inside, the decorator defines a function on the fly: the wrapper. This function is going to be wrapped around the original function so it can execute code before and after it. """
defthe_wrapper_around_the_original_function(): """ Put here the code you want to be executed BEFORE the original function is called """ print"Before the function runs"
# Call the function here (using parentheses) a_function_to_decorate()
""" Put here the code you want to be executed AFTER the original function is called """ print"After the function runs"
""" At this point, "a_function_to_decorate" HAS NEVER BEEN EXECUTED. We return the wrapper function we have just created. The wrapper contains the function and the code to execute before and after. It’s ready to use! """ return the_wrapper_around_the_original_function
# Now imagine you create a function you don't want to ever touch again. defa_stand_alone_function(): print"I am a stand alone function, don't you dare modify me"
a_stand_alone_function() # outputs: I am a stand alone function, don't you dare modify me
""" Well, you can decorate it to extend its behavior. Just pass it to the decorator, it will wrap it dynamically in any code you want and return you a new function ready to be used: """
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function) a_stand_alone_function_decorated() """outputs: Before the function runs I am a stand alone function, don't you dare modify me After the function runs """
""" Since when you are calling the function returned by the decorator, you are calling the wrapper, passing arguments to the wrapper will let it pass them to the decorated function """
@a_decorator_passing_arguments defprint_full_name(first_name, last_name): print"My name is", first_name, last_name
print_full_name("Peter", "Venkman") """outputs: I got args! Look: Peter Venkman My name is Peter Venkman """
defa_decorator_passing_arbitrary_arguments(function_to_decorate): # The wrapper accepts any arguments defa_wrapper_accepting_arbitrary_arguments(*args, **kwargs): print"Do I have args?:" print args print kwargs # Then you unpack the arguments, here *args, **kwargs # If you are not familiar with unpacking, check: # http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/ function_to_decorate(*args, **kwargs)
import functools defbar(func): # We say that "wrapper", is wrapping "func" # and the magic begins @functools.wraps(func) defwrapper(): print"bar" return func()