Python MagicCodec 0.1(更新到 0.11)

Posted by tjwei on 星期四, 2月 07, 2008 with 2 comments
這個是基於 PEP 263 弄的 python meta programming 小玩意。
包含兩個神奇編碼 zhpy 跟 PyLua。 MagicCodec 0.1 Download
(*更新 0.11)
安裝玩 MagicCodec 之後,下面這段會變成完全合法的 Python 程式
# encoding: zhpy_utf8
吼叫="啦啦啦"
印出 吼叫
執行 '印出 "再%s一次"%吼叫'
這個也是
# encoding: lua
i=10
function run(func) repeat func() until i==0 end
run(function () print("Hello!",i) i=i-1 end)
直接用 python 執行,或者用滑鼠點 xxx.py 就可以執行了。
MagicCodec 裡面包含的 zhpy 基於 zhpy 1.4,但是大量修改過了(幾乎全部改掉)。
有幾個修改的重點:
  1. 直接用 re 來做 tokenizer。殺雞不用牛刀,原來的 zhpy 用 pyparsing 。雖然說 pyparsing 提供很方便的功能來分解字串,但是類似的功能直接參考 python bnf 用 re.sub 來做,反而更簡單。
  2. 改掉許多重複的程式碼。原來 zhpy 有非常多的程式碼,重複好幾次。tw 的了一個函數,cn 的又寫一個函數。這樣維護起來很難。
  3. zh_exec 的功能和 exec 不同。我將他改成了比較符合原來 exec 行為的程式碼。改完後,原來的 zhpy_commandline 會爛掉,但實際上,會爛掉反而是 exec 的正確行為。
  4. 「執行 」我還是直接翻成 「exec zhpy.dec <<」,因為 zh_exec 是函數,跟指令 exec 的語法不同。
  5. type(x) == type("") 這類, 改成 isinstance(x,str)
另外一個重要的不同是改以 source code encoding 導向,將 zhpy 視為 python 的一個 codec,而不是另外一個 python 的實做。所以有許多差異。
  1. 用 MagicCodec 取代 zhpy_commandline,因為直接用 python xxx.py 就能執行了。而不用 zhpy xxx.py
  2. 用 excepthook 取代 try_run。
  3. 另外增加 PyOS_Readline hook,這樣 python 的命令列可以直接變成 zhpy 的命令列。所以取代原來執行 zhpy ,改用執行 python ,然後你 import zhpy.hooks;zhpy.hooks.setup_all() 就可以直接執行中文的程式碼。
  4. python win 也行,用前面的 zhpy.hooks 就可以了。
  5. idle 不行。因為 idel 是分離式的。如果你在 MagicCodec 的 __init__ 或者執行 idle 前執行 zhpy.hooks.setup_all(),就可以。
  6. idle 編輯器讀取 zhpy codec 的程式碼會解碼。所以會有問題。(所以 MagicCodec 也不永遠比較好)
  7. import 比較單純。原來 zhpy import hook 就不錯了。但是現在更好,因為不用修改, python 就能直接 import zhpy 的 module。原因很簡單,因為有 MagicCodec 之後的 zhpy 程式碼是合法的 python 程式碼。
但是還是有很多東西不行。
像是
# encoding: zhpy_utf8
吼叫="啦啦啦"
印出 吼叫
執行 '印出 "再%(吼叫)s一次"%locals()'
就會失敗,這個不難解決,只要用另外的 hook 包住 locals, globals, setattr, getattr 等。__dict__比較麻煩一點,這個是 mataclass 可以hook的。


更新(2008-02-28):由於網友 tocer 的反應,找到了好幾個 bug。
我其實有好幾個 Ubuntu 的機器,不過之前太懶,所以都沒有測試過。
所以雖然有考慮到, Linux 應該會有的狀況,不過都是用「想的」。
我們都知道,寫程式這樣是不行的。一測之下,果然 bug 連連。
第一個問題是好幾個檔案的權限設定有問題,windows 下還好, linux 下一般使用者就出問題了。
第二點主要是 encoded file 的問題。裡面幾個 return,雖然我是用很保守的 hook 法,但至少要傳回一些東西吧!另外還有一個語意上面的 bug 就是了。就是因為我要用保守的方式,只 hook,真正原始 file 形式的 sys.stdout/sys.stderr。所以語意應該是
if type(f) !=file: return f
才對,而不是
if type(f)==file: return
至於為什麼原來在 cygwin 上可以跑?我就不清楚了。現在剛好我手上又變成沒有 cygwin 機器了。搞不好 0.11 在 cygwin 上變成不能跑。
不過不管怎麼樣,這裡只是 display hook 上面的問題而已。最多就是顯示出問題。

Ubuntu 上建議使用有顯示 UTF8 能力的 Terminal。

最後,Ubuntu 上錯誤顯示會失效,因為 sys.excepthook 已經被其他 package 搶走了。我用很保守的策略來搶 excepthook,所以別人搶了,我就讓給別人。當然,你可以設定為強迫 excepthook(看程式碼)。
所以 hello.py 的錯誤展示有點多餘。

另外,還有一點小改動就是不再像 0.1 那樣 hook zhpy_codec 的 decode,只 hook streamReader。


更新(2008-03-01):
zhpy 1.5 已經出了,我雖然還沒有仔細看,不過應該有一些有趣的進展。
Categories: