I'm perhaps dubious that this is a good use case for decorators, but here:
import string
SelfClosing = object()
def escapeAttr(attr):
    # WARNING: example only, security not guaranteed for any of these functions
    return attr.replace('"', '\\"')
def tag(name, content='', **attributes):
    # prepare attributes
    for attr,value in attributes.items():
        assert all(c.isalnum() for c in attr)  # probably want to check xml spec
    attrString = ' '.join('{}="{}"'.format(k,escapeAttr(v)) for k,v in attributes.items())
    if not content==SelfClosing:
        return '<{name} {attrs}>{content}</{name}>'.format(
            name = name,
            attrs = attrString,
            content = content
        )
    else:  # self-closing tag
        return '<{name} {attrs}/>'
Example:
def makeBoldWrapper(**attributes):
    def wrapWithBold(origFunc):
        def composed(*args, **kw):
            result = origFunc(*args, **kw)
            postprocessed = tag('b', content=result, **attributes)
            return postprocessed
        return composed
    return wrapWithBold
Demo:
@makeBoldWrapper(attr1='1', attr2='2')
def helloWorld(text):
    return text
>>> print( helloWorld('Hello, world!') )
<b attr2="2" attr1="1">Hello, world!</b>
The common misconception with decorators is that the parameters (attr1=...) are parameters to the decorator @myDecorator; that is not the case. Rather the result of the function call myDecoratorFactory(attr1=...) is calculated as someresult and becomes an anonymous decorator @someresult. Therefore 'decorators with arguments' are actually decorator factories that need to return a decorator as a value.