Search code examples
pythonpython-decorators

Decorators when the decorator function takes two arguments


I am trying to learn decorators, so I have implemented the following example, where I am trying to create contents inside a specific tag.

def content_decoration(func1):
    def inner_function(name, c_decorator, tag):
        return '<{1}> {0} </{1}>'.format(func1(name, c_decorator), tag)
    return inner_function

@content_decoration
def return_decorated_content(content , con_decorator):
    return '{0} {1}'.format(content, con_decorator)

return_decorated_content('Content', ' content_addition', 'p')

The output of the above command would be: '<p> Content content_addition </p>'

However I find it a bit difficult, when I need to decorate both the content and the tag itself. For example, we have the following code:

def decoration(func1, func2):
    def inner_function(content, tag, content_decoration=None, tag_decoration=None):
        return '<{1}> {0} </{1}>'.format(func1(content, content_decoration ), func2(tag, tag_decoration))
    return inner_function

def name_decoration(con, con_decor):
    return '{0} {1}'.format(con, con_decor)

def tag_decoration(tag, tag_decor):
    return '{0} {1}'.format(tag, tag_decor)

Without the use of decorators we would have:

print decoration(name_decoration, tag_decoration)(content='Alice', tag='h1', tag_decoration='fontsize=12', content_decoration='')
# or
print 
function = decoration(name_decoration, tag_decoration)
print function(content='Bob',  content_decoration='Smith', tag='p')

which yields:

<h1 fontsize=12> Alice  </h1 fontsize=12>

<p None> Bob Smith </p None>

but how can I achieve the same result using the python syntactic sugar?


Solution

  • You can declare the name and tag functions above the function to be decorated and pass as parameters to the outer decorator:

    def decoration(func1, func2):
      def wrapper(f1):
         def inner_function(content, tag, content_decoration=None, tag_decoration=None):
           return '<{1}> {0} </{1}>'.format(func1(content, content_decoration ), func2(tag, tag_decoration))
         return inner_function
      return wrapper
    
    def name_decoration(con, con_decor):
       return '{0} {1}'.format(con, con_decor)
    
    def tag_decoration(tag, tag_decor):
       return '{0} {1}'.format(tag, tag_decor)
    
    @decoration(name_decoration, tag_decoration)
    def get_html(content, tag, content_decoration=None, tag_decoration=None):
       return 
    
    print(get_html(content='Alice', tag='h1', tag_decoration='fontsize=12', content_decoration=''))
    print(get_html(content='Bob',  content_decoration='Smith', tag='p'))
    

    Output:

    <h1 fontsize=12> Alice  </h1 fontsize=12>
    <p None> Bob Smith </p None>
    

    Or, you can use lambda functions to save space:

    @decoration(lambda con, con_decor:'{0} {1}'.format(con, con_decor), lambda tag, tag_decor:'{0} {1}'.format(tag, tag_decor))
    def get_html(content, tag, content_decoration=None, tag_decoration=None):
       return