發表文章

目前顯示的是 五月, 2011的文章

在命令列執行有載入 django 相關模組的程式

剛用 django 時會有個困擾, 不透過 manage.py 無法執行有 import django modules 的 scripts。後來有找到 django-standalone, 可以方便在其它 scripts 內使用 django modules。不過我並不需要執行 manage.py 的其它 command, 而是單純想在命令列執行 scripts。以這需求來說, django-standalone 有點冗。

今天仔細地追了一下前因後果, 發覺解法很簡單, 必須做兩件事:
設環境變數 DJANGO_SETTINGS_MODULE=APP.settings要在載入 module 的路徑中加上 django project 的根目錄, 即放 APP 的位置所以若 myscript.py 有使用 django moduels (比方說 django.db.connection), 執行的方式就是:
$ PYTHONPATH=.. DJANGO_SETTINGS_MODULE=APP.settings myscript.pymyscript.py 位在 project root。明白運作方式後, 做起來很簡單。

不設 DJANGO_SETTINGS_MODULE 的話會出現下面的 exception:
Traceback (most recent call last): File "/.../site-packages/django/db/__init__.py", line 14, in if not settings.DATABASES: File "/.../site-packages/django/utils/functional.py", line 276, in __getattr__ self._setup() File "/.../site-packages/django/conf/__init__.py", line 38, in _setup raise ImportError("Settings cannot be imported, because environment variable %s is undefined."…

隨手亂搞: 「逆向工程」改 Chrome Extension

原本想改 RePlurk Chrome, 改成我自己慣用的輸出格式, 到作者的 Blog 找原始碼, 發覺下載位置已掛了。不知道要怎麼採正規方式解封 Chrome extension 再重包。索性來玩看看比較髒的改法。
從 Chrome 執行檔的 link 找到 Chrome 放的位置在 C:\Users\MY_ACCOUNT\AppData\Local\Google\Chrome\Application 。 再從此找到 extensions 放在 C:\Users\MY_ACCOUNT\AppData\Local\Google\Chrome\User Data\Default\Extensions。看到一堆亂碼的目錄, 一個個進去看, 找到 RePlurk Chrome 的目錄, 和關鍵的原始碼: RePlurk.js參考作者原本參考的 Greasemonkey 的 RePlurk, 了解大概的格式, 明白要改的東西只是最後輸出那行對照 RePlurk.js 的內容, 很快就搞定了。和原本猜想的一樣, 關掉 Chrome 再開啟 Chrome, 會重載入所有 extensions, 然後就OK啦。整體來說還滿順利的, 花的時間應該比我寫這篇的時間還短, 運氣不錯。或著說, 我寫隨手記的速度還是太慢了, 要好好改進啊 ......。

小技巧: 用看不見的字元分隔資料

處理文字時, 偶而會需要將類似的東西串在資料庫表格的一個欄位裡或文字檔的一行文字裡。為了避免分隔符號和別的文字衝到, 從同事 P 那學到一個不錯的小技巧: 用看不見的字元分隔, 比方說 unicode 的 1 ~ 5 等。

用 Python 寫就是 "\u0001", 用 mysql 則是 char(1), VIM 會用 ^A 表示 (\u0002 則用 ^B), 最妙的是, Firefox 會用一個小方格在裡面填入 0001 表示它, 所以寫到資料庫後, 用 phpMyAdmin 看也不會有問題, 真是太貼心了。通常為了方便, 可能會用 "\u0001\n" 表示, 這樣在 phpMyAdmin 裡看時, 也會換行表示。

其它應用方式, 像是填入字串表示未定義時, 可以用 "\u0001UNDEFINED", 避免單用 "UNDEFINED" 可能會和這樣的內文衝突。而要用 mysql 取值時, 可配合 concat 表示: concat(char(1), "UNDEFINED")。

MySQL 交集的寫法和效率

之前在這篇提到用 union all + group by + having 的方式寫交集, 當時沒測效率。最近剛好有個簡單例子, 比了一下效率。我要從 T1、T2 兩個表格取出欄位 F, 兩個表格各自的資料有重覆的 F, 我想找出 T1、T2 的  F 的共通值。

寫法如下:
SELECT DISTINCT F FROM T1 where F in (SELECT DISTINCT F FROM T2)SELECT F, COUNT(*) FROM (SELECT DISTINCT F FROM T1 UNION ALL SELECT DISTINCT F FROM T2) AS t GROUP BY F HAVING COUNT(*) = 2;T1、T2 各有數萬筆資料。測的結果是第二個寫法瞬殺, 第一個寫法等個十秒沒結果, 我就懶得等了。

原因出在第一種寫法的 sub-query 被當作 dependency query 來處理, 變成每一筆資料都來個 sub-query。不過 MySQL 會有 query cache, 照理說不會慢到這種程度才對, 有機會再去了解詳細運作過程吧。至少藉這機會確定了用 union all 的寫法較好。

讓 vim 暫時 highlight 指定的關鍵字

圖片
在讀程式碼時, 常需要暫時追踪特定變數, 比方說 class Foo 裡有個 self.client 用做連線, 想追踪 self.client 是如何被產生、設定、使用。以前我會在 client 上按 * 搜尋這個字, vim 裡有設 set hlsearch, 自然會被 hilight。這個作法有兩個缺點:
一次只能特別標記一個字。游標會跑掉, 得再按 ? 跑回來。剛才想到, 其實可以寫個 nmap, 按個鍵就自動 highlight 目前的關鍵字。參考 cscope 的巨集指令, 總算試出來了, 結果如下:
~/.vimrcnmap <leader>* :syn match TempKeyword /\<<C-R>=expand("<cword>")<CR>\>/<CR> nmap <leader>c :syn clear TempKeyword<CR> hi TempKeyword ctermfg=red 注意, 若你載入的 syntax file 或其它 vim script 有執行 :syntax clear 的話, 要將 hi TermKeyword 那行移到 :syntax clear 之後。像我用的 syntax/python.vim 就有執行 :syntax clear。
用法<leader> 預設是對到反斜線 ("\"), 若沒設 <leader> 的話, 就是在想 highlight 的字上按 \*, 就會用紅色顯示這個字, 可以在多個字上按 \*, 效果會累加。不想看的時候, 按 \c 清掉所有 highlight 的字。

下面是使用前後的對照圖 ( 游標移到 auth_type 後按 \* ):



備註<C-R>=expand("<cword>")<CR> 是關鍵, 這段程式碼會取出目前游標所在的字, 展開後填在命令列上。之後再來詳細研究它的結構。<C-R>= 、 expand 、 <cword> 和 <CR> 四個拆開看我都懂, 但合在一起為何有這個效果, 就看不懂了。

2011-05-17 更新…

Perl 隨手筆記

最近因緣際會之下寫了一小段時間的 perl, 筆記一下一些基本心得, 搞定後大概很長一陣子都不會再碰 perl 吧。這次學的方式比較隨興, 大概在網上要用到時查查文件, 還有看看 DK 在 github 的程式, 不像以前會好好找一本書仔細讀。藉機體會不同學程式的方法, 目前仍是一知半解, 大概寫起來會動的狀態, 感覺還不錯。

關於 package: perl的包(package)和模块(PM) 介紹得很清楚, 另外自己試了一些東西:
package/module 和 目錄/檔案 對應, 這點和 java、python 差不多module 要和檔名同名, 慣例是用 WikiWord 命名module 最後一行要是 1perl -I MODULE_PATH ... 會在 MODULE_PATH 下檢查 載入的 module。注意 -I 如同 java 的 -cp, 要放在其它參數之前。相較之下, python 用 PYTHONPATH 有些不直覺, 不過配合 PYTHONPATH=... python ... 的方式執行, 也不會太不方便開頭必寫 use strict;use warnings;use utf8;查函式 perldoc -f FUNCTION, 比方說 perldoc -f join
注意 perl 有傳值和傳參考之分, python和 java 只傳參考簡單多了。現階段還沒感受到區分傳值和傳參考帶來的好處。

符號會影響到取值的方式, 目前大概知道意思, 不過很多情況是是亂試試到對。之後若要再寫 perl, 該先弄清楚這點。

幾種函式開頭的慣例寫法 my $first_argument = shift || croak;my ($a, $b, $c) = @_;Croak or Die? 說明兩者的差別, 看起來 croak 比較好用一點, 不過我會更想像 Python 那樣 dump stack trace。似乎後來版本的 perl 有內建 croak (在 Carp 裡)。

小結: 在徹底地學過 python 體系後, 現在學新語言時比較知道該學的項目, 還有拿捏學習的順序。知道別妄想一次到位, 要能忍受一邊寫出不道地的程式, 一塊塊地學起來。也更深刻體會到, 改用別的語言, 熟悉度落差的影響比預想得嚴重, 可當日後選擇語言的參考依據。

Python 生態圈

身為一名 Python Guy, 怎麼可以連發兩篇 Perl 的心得文卻沒發 Python 的心得文呢? 來補寫篇 Python 相關體系, 算是這兩年來寫 Python 的心得吧。

入門書Python Essential ReferenceDive into Python見《學 Python 的入門書》的介紹。安裝環境pip + virtualenv: 以前用 easy_install, 現在已轉為以 pip + virtualenv 為主。可幫整個 OS 或個人裝自己用的函式庫。這一年來兩者版號跳得很快, 原本就夠好用了, 期待它們的後續發展。PyPI: Python 的 package 集散中心, 不過也很少會上來找東西。大多 google 一下, 就 pip instrall PKG。若 PyPI 有的話, 自然會裝起來, 沒有的話, 再自己找官方 VCS 網址, 或下載 tarball。開發工具vim: 不需多介紹的神兵利器。相關設定: 設定顏色。ipython: 查函式和快速測試的好幫手。不知其它語言裡有沒有類似順手的工具。pycscope: python 版的 cscope, 據說會準一點。ipdb, 用 ipython 強化後的 debugger。
文件系統Sphinx: 超精美的文件產生工具。Epydoc: 精美的 API 手冊產生工具, 有針對 dynamic typing 的特性產生參照連結。測試工具nosetests: 執行測試碼的好幫手, 強大之處見這裡的說明。unittest2: 比 unittest 方便不少, 並且有和 unittest 向下相容, 見這裡的說明。部署工具fabric: 取代 shell script 的「框架工具」, 方便跨機器以及組合不同細項工作。版本管理mercurial: 雖說程式語言和版本管理工具並無相關, 但 Python Guy 似乎大多喜歡用 mercurial。bitbucket 提供線上使用 mercurial, 但我一開始就用 Google Code 和 Github, 就沒在用它了。常用函式庫大概列一下, 這種清單太多, 也超出我能力所及。 lxml: 處理 XML 和 HTML, 支援 xpath 和 css path, 底層用 C, 速度勝過其它類似的函式庫。simplejson (2.6 後已…

從 Google Reader 救回資料並匯到 Blogger

之前服務 http://fcamel.twbbs.org/ 的站掛了, 好險之前有用 Google Reader 備份, 寫個程式就可以輕鬆地救回來。備份方式很簡單, 啟用 Blog 時在 RSS/ATOM 裡輸出全文, 再到 Google Reader 訂閱, 這樣 Google Reader 就有全文了。

要從 Google Reader 讀出全部資料相當容易, 只要一個 URL 就能下載包含全部內容的 XML 檔:
http://www.google.com/reader/atom/feed/http://YOUR_BLOG_FEED?n=100000我寫了個小程式讀 XML 檔, 用 Blogger API 匯入資料, 有興趣使用的人可以見這裡的說明

Java 執行 Runtime.exec() 時, 沒讀取 stdout 可能會造成 deadlock

遇到這問題 google 了一下, 看到 When Runtime.exec() won't 才知道 java.lang.Process 裡有寫:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.沒寫在文件裡, 還真想不到啊。偷懶的解法是執行時將 stdout 和 stderr 導到 /dev/null。注意若想在 exec() 裡重導 IO, 直接執行指令加上重導符號不會有作用。正確的作法如下:
String[] cmd = {"/bin/sh", "-c", "/bin/ls > out.dat"}; Process p = Runtime.getRuntime().exec(cmd); 注意要用 String[] 的方式呼叫 exec, 這樣才能將 "/bin/ls > out.dat" 合在一起傳給 /bin/sh; 用 String 的方式傳一整個字串會出錯, 因為傳單一字串時, Java 會先切開字串再用 String[] 的方式執行它, 而 /bin/ls -c 只接受下一個參數, 不會看到後面的 ">" 和 "out.dat"。

Perl 的 reference

上網看了些入門文件, 自己試一陣子, 總算弄懂 Perl 的 reference, 不懂這個東西無法好好地寫函式。貼個程式備忘, 到頭來, 還是精簡的程式範例最好懂。主要是參考Perl 學習手札 - 14. 參照 (Reference)

Perl 的參考和 C 的指標差不多, {$p} 相當於 C 的 *p 取出指標指向的變數, ${$p}{key} 寫起來太麻煩, 可改用 $p->{key} 比較好寫, 這點也和 C 的 -> 同樣。取參考用 \ 類似 C 的 &, 像是 \%h 和 \@a 各別是取出雜湊 %h 和陣列 @a 的參考。另外要注意的是 Perl 會看 @、% 決定變數的意義, 等號左邊用什麼符號, 就決定它的語境。

另外 Perl 有 GC 的機制, 不用擔心從函式內傳回參考後, 資料會不見。
陣列和參考@a = qw/x y z/; print @a, "\n"; # xyz # reference of an array $p = \@a; print $p, "\n"; # ARRAY(0x605050) print "\$p[0]: ", $p[0], "\n"; # $p[0]: print "\${\$p}[0]: ", ${$p}[0], "\n"; # ${$p}[0]: x print "\$p->[0]: ", $p->[0], "\n"; # $p->[0]: x unshift @{$p}, "w"; print @{$p}, "\n"; # wxyz # [] $p = []; print "\$p: ", $p, "\n"; # $p: ARRAY(0x6326a0) push @{$p}, "q"; print ${$p}[0], &qu…

VirtualBox 調大 guest OS 的螢幕解析度

這篇有清楚的圖解和文字說明, 摘要如下:
在開啟 guest OS 的情況下, 在 guest OS 的視窗上方點「裝置」 -> 「安裝 Guest Additions」。不要像我一樣傻傻地一直在 VirtualBox 管理員視窗一直找都找不到開 terminal, 切到 /media/cdrom0 目錄下sudo ./autorun.sh。若結果不如網頁裡提的畫面, 改用 sudo ./VBoxLinuxAdditions.run重開 guest OS點 System -> Preference -> Screen resolution (或是 Monitor / Display, 看你的 Ubuntu 版本), 會有更多種解析度可選。不過我弄好後它就自動改選最大的了。理論上中間執行 autorun.sh 後要 OK, 但我執行的結果是沒反應。於是改用 sudo sh -x autorun.sh 看 shell script 執行過程, 發覺它沒有成功執行, 最後有行錯誤訊息要我自己執行 ./VBoxLinuxAdditions.run, 但因為原本執行 autorun.sh 會跳出另一個視窗, 顯示錯誤訊息後又自己關掉視窗, 最好是看得清楚 .......。

expr 充當簡單 regexp 工具

有時候會需要用一下簡單的 regexp 處理字串, 以前我會因此用 perl -ne ..., 後來太久沒寫 perl 又忘了語法, 遇到這種情況就覺得頗困擾的。今天在讀別人的 shell script 時發覺 expr 竟然也有基本的 regexp 功能!!

以下是 man expr 的部份內容:
STRING : REGEXP
Pattern matches return the string matched between \( and \) or null; if \( and \) are not used, they return the number of characters matched or 0.附上相關例子:
$ expr "hello world" : "hello.*"
11
$ expr "hello world" : "hello"
5
$ expr "hello world" : "hello \(.*\)"
world有了 expr, 以後湊指令方便多啦

Java 的 JSON lib: json-simple

似乎 Java guy 偏好 XML 的做法, JSON 相關說明好像比較少, 像 Python 2.6 後直接內建 json, 2.5 前也有公認的 simplejson。找了一會兒, 看起來 json-simple 最好用, 輕巧簡單。官網還有搜集一些 blog 提到 json-simple 的文章, 其中這篇 A Review of 5 Java JSON Libraries 還不錯, 列了表格說明作者重視的項目, json-simple 看起來的確不錯。我試用後也覺得頗滿意的, JSON 的 object 直接對到 Map-like 的 JSONObject, list 對到 List。和 Python 用起來的差別, 就是取出資料後自己要轉型成對應的型別, 不過對 Java 來說, 似乎也是理所當然的事。

使用 Virtual Box 從 host OS 連向 guest OS

2011-06-05 更新 剛發現可以透過 GUI 介面直接從 Network -> Advanced -> Port forwarding 裡新增 forwarding rules, 以下的記錄就當歷史吧......。 ( 原文如下 ) 之前在 Windows 下試過一些寫 Python 的方案, 最後得到的結論是: 裝 andLinux 再用 putty 連 localhost 開 screen 最好用!! 姑且不論這種作法到底還算不算是「在 Windows 下寫 Python」, 我個人覺得這樣滿順手的, 而且只要習慣一種開發環境即可。不幸的是, andLinux 無法裝在 64bit Windows 下, 只好改裝 VirtualBox 再裝 Ubuntu 10.04。

裝 VirtualBox 和 Ubuntu 10.04 超級簡單, 就和裝一般軟體沒兩樣。反正是 VM, 而且是自己練習 coding 用的系統, 直接一個大 partition 搞定, 什麼設定也不管, 沒多久就裝好了。裝好後如同 andLinux, 網路都設好了, guest OS 透過 host OS 用 NAT 的方式可連到 Internet。但是, host 預設無法連回 guest, 於是找了一下設法。

參考 Howto Access via ssh a Virtualbox Guest machine 的說明和留言的指示, 外加一些 try & error, 整理出方法如下:
在 guest OS 用 ifconfig 找出網卡名稱 (如 eth0)在 guest OS 用 dmesg 配合網卡名稱找出 device (?) 類型 (dmesg | grep eth0), 可能會找到 pcnet 或 e1000。我的情況是 e1000在 host OS 的命令列執行指令 VBoxManage (Windows 的見下面補充說明): VBoxManage setextradata "GuestName" "VBoxInternal/Devices/e1000/0/LUN#0/Config/ssh/HostPort" 2222 VBoxManage setextradata "GuestName" …