賴勇浩(http://laiyonghao.com)
一
先來看兩句代碼
record = cursor.execute('select * from tbl where id = 123456').fecth_all()[0]msg = struct.unpack('!I', buff)[0]
不知道大家怎麼樣看,我覺得有這兩個 [0] 跟在後面,還是蠻醜的。其實可以利用 Python 指派陳述式簡寫:
record, = cursor.execute('select * from tbl where id = 123456').fecth_all()msg, = struct.unpack('!I', buff)
注意 record 和 msg 後面的逗號,可以利用它讓 Python 把這個指派陳述式理解為多對多的賦值,但可省去後續的 [0] 了。
這種寫法,據我以前的同事測試,比使用 [0] 要慢上 20% 左右。如果你很在意,建議使用之前的寫法。另外,兩種寫法到底哪個更漂亮、更 Pythonic,也沒有定論,但我喜歡後者。
二
用 ConfigPaser 是解釋 ini 檔案的利器,因為有這麼好用庫,所以我寫的項目基本上都是用 ini 檔案來配置的。ConfigParser 支援 DEFAULT 節,寫在 DEFAULT 節中的配置項可以作為實參替換後續的引用,比如在我之前提過的“棋牌OnWeb”項目中,我們使用這樣的設定檔:
[DEFAULT]base_path= /home/qipai-v1/src/server[policy]switch = onport = 18843path = %(base_path)s/hall/config/flashpolicy.xml
其中 policy.path 的值取出來的時候就變成了 /home/qipai-v1/src/server/hall/config/flashpolicy.xml,ConfigParser 會自動為你做好替換。
不過在這裡要講的不是這個技巧。如果你有留意到 ConfigParser.ConfigParser 類的那個 defaults 參數,那就是真正的我要講的東西了。defaults 參數可以補充 ini 檔案中 DEFAULT 檔案的不足,能夠運行時再決定變數的實參。比如在“棋牌OnWeb”項目中,所有的遊戲進程都由一個叫 desk 的程式來服務的,它通過命令列傳入的參數載入不同的外掛程式實現不同的商務邏輯。比如 desk --game-name=doudizhu 可以運行一個鬥地主的服務,desk --game-name=xiangqi 則是中國象棋。顯然,為了方便通過日誌分析錯誤,有必要把日誌按遊戲、房間和桌子分離開來,比如 xiangqi-1-10.log 表示象棋遊戲的房間1桌子10的進程的日誌,這時候如果使用內建的 logging 模組來記錄日誌,我們可以這樣配置它:
[handler_game]class=handlers.TimedRotatingFileHandlerformatter=commargs=('log/%(game_name)s-%(rid)d-%(did)d.log', 'midnight', 1, 30)
在程式啟動並執行時候,我們這樣初始化 logging:
logging.config.fileConfig(conf, defaults = dict(game_name = game_name, rid = rid, did = did))
把 rid 和 did 通過命令列參數傳過來即可。之所以能夠這樣做,完全因為 logging 也是使用 ConfigParser 來解釋它的設定檔的呀,Python 吸引人之一的地方就是這樣的:盡量重用,更加靈活。