Greg> Also, I'm having second thoughts about this: >> StringWidget's 'size' and 'maxlength' >> attributes and constructor keyword arguments are gone, as are >> TextWidget's 'rows', 'cols', and 'wrap', and so forth. Greg> because those constructor keyword args are just darn convenient. Ah... so the pendulum begins to swing back in the other direction. ;-) Dictionaries are fine, and relative to many other languages they are very light on the syntax, but they are still not quite as convenient as using keyword args. How about you allow both keyword args and an explicit attribute dict? That way, for the oddball stuff which clashes with Python syntax you go the extra step and use the dictionary, but for normal usage, keyword args do just fine: htmltag('input', type='text', size=20, maxlength=40) htmltag('textarea', rows=30, cols=80) htmltag('body', bgcolor='#fff', attrs={'class': 'mainpage'}) Most of the time you won't need the attrs argument, but when you do encounter a recalcitrant attribute name, you won't have to remember how to sneak it by the Python parser. Of course, purists are free to just use attrs: htmltag('input', attrs={'type': 'text', 'size': 20, 'maxlength': 40}) htmltag('textarea', attrs={'rows': 30, 'cols': 80}) htmltag('body', attrs={'bgcolor': '#fff', 'class': 'mainpage'}) In htmltag() all you'd need to do (I think) is def htmltag(name, attrs=None, **kwargs): if attrs is not None: kwargs.update(attrs) then use kwargs as the source of all attribute/value pairs. Skip