Handling objects and arrays simply in this tagging library I have written this little tagging module to make it easier to generate small html snippets on the fly. The examples below show how this make things a bit easier. My question is about the handling of tags that contain either a single element like text or a list of other elements, like the tr element in the second example. At the moment, the code has to jump though some unpythonic loops to handle the different cases. How do I write code that handles either a single thing or a list of those things with one function in an elegant way?

""" Supplies some utilities for creating html documents manually

&gt;&gt;&gt; print(h1('test'))
&lt;h1&gt;
test
&lt;/h1&gt;

&gt;&gt;&gt; print(table([tr([td('d1'), td('d2')]), tr()]))
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
d1
&lt;/td&gt;
&lt;td&gt;
d2
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr /&gt;
&lt;/table&gt;
"""
from __future__ import print_function

class tag:
    """ represents an html tag - specifically used to create outputs for web pages

    Basic usage - create a "test" tag:

    &gt;&gt;&gt; print(tag('test'))
    &lt;test /&gt;

    Attributes can be specified as a dictionary

    &gt;&gt;&gt; print(tag('test', attributes={'prop': 'value'}))
    &lt;test prop='value' /&gt;

    The real benefit - tags can be nested, allowing the python interpreter to track closing tags:

    &gt;&gt;&gt; print(tag('test', tag('inner')))
    &lt;test&gt;
    &lt;inner /&gt;
    &lt;/test&gt;
    """
    def __init__(self, name, contents=[], attributes={}):
        self.name = name
        self.contents = contents
        self.attributes = attributes
    def __str__(self):
        tagcontents = self.name
        if len(self.attributes) &gt; 0:
            attrstring = " ".join("%s='%s'" % kv for kv in self.attributes.items())
            tagcontents += " " + attrstring

        if self.contents:
            if hasattr(self.contents, '__iter__') and not hasattr(self.contents, 'strip'):
                contentstring = "\n".join(str(i) for i in self.contents)
            else:
                contentstring = str(self.contents)
            return "&lt;%s&gt;\n%s\n&lt;/%s&gt;" % (tagcontents, contentstring, self.name)
        else:
            return "&lt;" + tagcontents + " /&gt;"
    def __repr__(self):
        return "tag(%s, contents=%s, attributes=%s)" % (self.name, self.contents, self.attributes)

def namedtag(t):
    """ create a named tag class - useful for standard html tags

    &gt;&gt;&gt; mytag = namedtag('mytag')
    &gt;&gt;&gt; print(mytag())
    &lt;mytag /&gt;

    """
    class n(tag):
        def __init__(self, contents=[], attributes={}):
            tag.__init__(self, t, contents, attributes)
    return n

h1, h2, p, table, td, th, tr, a = (namedtag(t) for t in ("h1", "h2", "p", "table", "td", "th", "tr", "a"))
The solution is to have contents always be a list. If we don't want to impose this onto the caller of the constructor, we have to use a variable number of arguments:

def __init__(self, name, *contents, **attrs):
   ...


Now the functions can be called as table(tr(td('d1'), td('d2')), tr()) or more generally:

foo("name", child1, child2, ... attr1=value, attr2=value, ...)


Then inside the function, contents will be a tuple and attrs a dictionary.



Otherwise, I find your inappropriate usage of OOP unnecessary. For example, the class n does not really add value, and violates the Liskov Substitution Principle – the constructor signature is incompatible with the parent class. Instead, use closures to provide a default argument:

def namedtag(name):
    return lambda *contents, **kws: tag(name, *contents, **kws)