Decorator

Buffer this pageShare on FacebookPrint this pageTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUpon
Reading Time: 2 minutes

Decorator Design Pattern in Python

Decorator Design Pattern in Python

Design Patterns Home
 

What is it?

The Decorator Design Pattern gives us a method to add new functionality to an object, dynamically. Python makes implementing this pattern relatively easier as compared to other languages, due to its builtin feature called decorators. It is a Structural Design Pattern as it eases the application design by identifying a simple way to add features to an existing object dynamically.


Why the need for it: Problem Statement

If you to add new features to an existing object without having to modify it, then you can opt for the Decorator Pattern.


Terminology

  • Decorator function: The decorator function takes an object, manipulates it using its own object and returns this latter object. For example, in the event of decorating a function:
  • def decoratorFunction(inputFunction):
    	def manipulateInputFunction():
    		capture return value of inputFunction
    		return manipulatedReturnValueOfInputFunction
    	return manipulateInputFunction
    
    @decoratorFunction
    def functionToBeDecorated():
    	# body of function
    	returns an object, say a string
    
    SIGNIFICANCE OF @ NOTATION
    Any call to functionToBeDecorated() BECOMES call to decoratorFunction() with functionToBeDecorated as its argument i.e. 
    functionToBeDecorated() BECOMES decoratorFunction(functionToBeDecorated)()
    
    For example:
    stringOne = functionToBeDecorated()
    BECOMES
    stringOne = decoratorFunction(functionToBeDecorated)()
    

Pseduo Code

Following is an example of pseudo code that decorates a function. The decorator function decorateMyFunction() takes a function as input and its return value is also a function. Before beginning, it is important to understand that functions, like everything else in Python, is an object.

def decorateMyFunction(originalFunction):
	'''Decorates a function by wrapping its return value in a pair of HTML paragraph tags.'''
	def addAdditionalText():
		obtain string returned by original function
		add text to the string
		return new string
	return addAdditionalText

@decorateMyFunction
def functionToBeDecorated():
	'''A simple function that returns a string.'''

# TESTING THE CODE
print( functionToBeDecorated() )             

How to implement it

Let's make the output of a function fancier by wrapping its return value with additional text. We will make use of the decorator annotation (@) provided by Python.

def decorateMyFunction(originalFunction):
	'''Decorates a function by wrapping its return value in a pair of HTML paragraph tags.'''
	def addAdditionalText():
		# Obtain string returned by original function
		textFromOriginalFunction = originalFunction() 
		# Adding new functionality to the function being decorated
		return "<p>" + textFromOriginalFunction + "</p>"
	return addAdditionalText

@decorateMyFunction
def functionToBeDecorated():
	'''A simple function that returns a string.'''
	return "Hi there!"

print( functionToBeDecorated() )                  # OUTPUT: <p>Hi there!</p>

Walkthrough of implementation

  1. The function declared after the @decorateMyFunction gets passed to the decorateMyFunction as argument.
  2. So, a call to functionToBeDecorated() becomes a call to decorateMyFunction(functionToBeDecorated).
  3. The decorateMyFunction() method returns the function called addAdditionalText. So, the addAdditionalText() function is called.
  4. The addAdditionalText() function captures the return value of the function supplied to it i.e. functionToBeDecorated(), and adds additional text to it.
  5. This manipulated string is returned and is eventually printed.

Related to: Adapter, Composite & Strategy


 

 

 

 


See also:

Buffer this pageShare on FacebookPrint this pageTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUpon

Leave a Reply