HTML タグ付き文字列を動的に生成する実装のリファクタリング
1年前に開発したアプリケーションの機能拡張に伴い、徹底的にリファクタリングしてやろうと気合を入れて改修中です。
そんな中、HTML タグ付き文字列を動的に生成する - forest book で書いた処理を、いま見返すと見た目があまりよろしくありませんね。もうちょっと格好良くリファクタリングしてみました。
def get_html(tag, **kw): """ >>> get_html("anchor", url="http://bit.ly/bT2kfY", name="forest book") '<a href=http://bit.ly/bT2kfY >forest book</a>' >>> get_html("input", type="text", id="blog_comment", name="comment") '<input type=text id=blog_comment name=comment />' """ func = {} func['anchor'] = get_anchor_tag func['input'] = get_input_tag return func[tag](**kw) def get_anchor_tag(**kw): """ >>> get_anchor_tag(url="http://bit.ly/bT2kfY", name="forest book") '<a href=http://bit.ly/bT2kfY >forest book</a>' >>> get_anchor_tag(url="http://bit.ly/bT2kfY", ... name="forest book", attr="value=1") '<a href=http://bit.ly/bT2kfY value=1>forest book</a>' """ kw.setdefault("attr", "") return "<a href=%(url)s %(attr)s>%(name)s</a>" % kw
Python 2.6 以上は format() メソッドを使った記述の方が良いそうです。
def get_input_tag(**kw): """ >>> get_input_tag(type="text", id="blog_comment", name="comment") '<input type=text id=blog_comment name=comment />' >>> get_input_tag(type="text", id="blog_comment", name="comment", ... attr='style="width:100px"') '<input type=text id=blog_comment name=comment style="width:100px"/>' """ kw.setdefault("attr", "") return "<input type={type} id={id} name={name} {attr}/>".format(**kw)
また Python 2.5 以上で collections.defaultdict を使うと、デフォルト値を生成するファクトリ関数を設定できます *1 。
def get_anchor_dd_mapping(d): """ >>> from collections import defaultdict >>> get_anchor_dd_mapping(defaultdict((lambda: ""), ... url="http://bit.ly/bT2kfY", name="forest book")) '<a href=http://bit.ly/bT2kfY >forest book</a>' """ return "<a href=%(url)s %(attr)s>%(name)s</a>" % d def get_anchor_dd_format(d): """ >>> from collections import defaultdict >>> get_anchor_dd_format(defaultdict((lambda: ""), ... url="http://bit.ly/bT2kfY", name="forest book")) '<a href=http://bit.ly/bT2kfY >forest book</a>' """ return "<a href={url} {attr}>{name}</a>".format( url=d["url"], attr=d["attr"], name=d["name"])
この例は setdefault() でも実装できる処理を置き換えているだけなので、あまり良い例ではありません。もっと詳しく知りたい方は defaultdict の使用例 を参考にしてください。
format() メソッドへ渡すときに、以下のように ** 引数を使ったりすると横着するなと怒られます。
... return "<a href={url} {attr}>{name}</a>".format(**d) ********************************************************************** File "operate_html_tag.py", line 50, in operate_html_tag.get_anchor_dd_format Failed example: get_anchor_dd_format(defaultdict((lambda: ""), url="http://bit.ly/bT2kfY", name="forest book")) Exception raised: Traceback (most recent call last): File "/usr/lib/python2.6/doctest.py", line 1241, in __run compileflags, 1) in test.globs File "<doctest operate_html_tag.get_anchor_dd_format[1]>", line 2, in <module> url="http://bit.ly/bT2kfY", name="forest book")) File "operate_html_tag.py", line 54, in get_anchor_dd_format return "<a href={url} {attr}>{name}</a>".format(**d) KeyError: 'attr' **********************************************************************