pythonでimport文で指定したクラスを動的生成したい
posted by jun-g at Tue, 03 Apr 2007 02:16 JST
ここんとこずーっと悩んでて解決方法がわからんのでブログで晒してみる。
pythonでMochiKit.DOMのcreateDOMみたいのがあったら便利かなと思って下記のようなクラスを書いた。
class Tag:
"""A base class of HTML tag."""
name = None
inline = True
container = False
def __init__(self, *nodes, **attributes):
self.nodes = nodes
self.attributes = attributes
def __str__(self):
return self.serialize()
def serialize(self):
text = ""
for node in self.nodes:
if isinstance(node, Tag):
text += node.serialize()
if not node.inline:
text += "\n"
else:
text += node
tag = "<" + self.name
attrs = map("=".join, [(x[0], "\"%s\"" % (x[1])) for x in self.attributes.items()])
if len(attrs) > 0:
tag += " " + " ".join(attrs)
if text == "":
tag += " />"
if self.container:
tag += "\n"
else:
tag += ">"
if self.container:
tag += "\n"
tag += text + "</" + self.name + ">"
return tag
サニタイズとか全然してないけど、とりあえずなのであまり気にしない。こいつから各タグのサブクラスを作っておくと、
class DIV(Tag):
name = "div"
inline = False
container = True
class A(Tag):
name = "a"
inline = True
container = False
下記のように使える。
>>> a = A("DaemonFreaks.com", href="http://www.daemonfreaks.com/")
>>> div = DIV("僕のサイト: " , a, style="border: 1px solid #000000;")
>>> print div
<div style="border: 1px solid #000000;">
僕のサイト: <a href="http://www.daemonfreaks.com">DaemonFreaks.com</a>
</div>
でもって、タグを全部クラスとして定義するのもアレなので、クラスを動的に生成する関数を作った。
from new import classobj
def _get_class(name, inline, container):
name = name.lower()
cls = classobj(name.upper(),
{"name": name,
"inline": inline,
"container": container})
return cls
で、各タグの名前、inlineとcontainerの設定を用意しておけば準備完了。
# name: (inline, contaier)
TAGS = {
"html": (False, True),
"head": (False, True),
"body": (False, True),
(省略)
"div": (False, True),
"span": (True, False)
}
後は、import文が呼び出された際に、「import *」なら定義内容すべてのクラスを、タグが指定されたなら指定タグのクラスをグローバル空間に展開するようにしたい。つまり、モジュール「html」内にこれらのコードが書かれていたとして、
>>> from html import HEAD, BODY >>> dir() ['HEAD', 'BODY'] >>> from html import * >>> dir() ['HTML', 'HEAD', 'BODY', (省略), 'DIV', 'SPAN']
のように動作させたい。
しかし、同一モジュール内で__import__をオーバーロードしたりihookを使用してみたものの、どうも期待どおり動作しない。同一モジュール内にオーバーロードの処理を書くと、そのモジュールがimportされた後に__import__がオーバーロードされてしまう(当たり前か…)。なので、モジュール内で自分自身を再度インポートするように記述するとなんとなく上手く動いてるような感じにはなる。
importされるモジュール側でimportをhookして、指定されているクラス(orモジュール)名を取得する方法は無いものか…。