$importでpythonのmoduleをimport出来るようにしてみた
今回はimport出来るようにしてみた。例えば以下の様にして使うことが出来る。そう言えば、前回の記事では使い方を説明していなかった。使い方は単純で zenmai.compile(d, module)
という感じで呼び出すだけ。注意点として順序は保持してもらう必要がある(dictknifeというのはyamlのloadに便利なutilityというだけなのでなくてもどうにかなる)。
from zenmai.actions import import_, from_ # これ if __name__ == "__main__": import zenmai import sys from dictknife import loading loading.setup() # xxx d = loading.loadfile(None) d = zenmai.compile(d, sys.modules[__name__]) # ここに渡したmoduleが触れる loading.dumpfile(d)
このようなコードを書いてあげると以下のようなyamlに対して
code: $import: math nums: ceil: $math.ceil: 1.5 floor: $math.floor: 1.5
以下のような出力を返すようになる。
nums: ceil: 2 floor: 1
微妙な点
ただ微妙な点が残っている。それは戻り値が出力として不要な階層の部分に不格好な記述が必要になる点。例えば、上の例で言うと、importを行う部分のところに code
と書いているが。これは実は何でも良い。呼ばれるactionで戻り値が何も返さなかった場合にはその階層自体がまるっと消えて無くなる。内部的には missing = object()
みたいなものを利用してあれこれしている。すごく汚い。
fromにも対応
実は import
の他に from
も対応している。例えばこういう感じも書ける。
code: $from: math import: - ceil - floor nums: ceil: $ceil: 1.5 floor: $floor: 1.5
予約語
ちなみに、from
や import
は予約語なので、pythonのコード上でこのような予約語のメソッドなどを定義できないかと思いきや実は普通にできる。ただしsyntax errorになるのでそれを迂回する必要はある。こういう感じ。
A = type("A", (), {"import": lambda self: "import!!"}) print(getattr(A(), "import")()) # import!! # print(A().import) syntax error
なんとなくの方針として、今回は、こういう汚い感じのコードは書かなくてすむようにしよう、ただし予約語のものもそのまま書けるようにしようという感じにすることにしたので。実装では keyword.iskeyword
を使って分岐している。from
が自動的にfrom_
を探して呼び出すということにした。予約語を見つけてくれるkeyword packageはたまに便利だったりする。