Skip to main content

· 3 min read

NS-3? 跟 PS3 沒關係 NS (Network Simulator)-3 是已經主宰網路模擬界多年的 NS2 的繼任者。原來 NS-3 早已悄悄上路。值得花點時間來瞧瞧 NS-3 有什麼改進.

初接觸的感覺還不錯,NS-3 有個比 NS2 規範多的網站, 拿掉 otcl 介面描述語言,使用 C++ 模組化元件並直接用 C++ 來描述拓樸,有公開可參與的程式碼,有定期的版本發佈規劃, 而且有 Python Binding (用 Python script 來描述拓樸,與控制模擬的互動) 的規劃!

有 Python Binding 這件事其實看了他們的網站並不那麼意外. NS-3 專案程式碼用 mercurial 管理 (用 python 寫的分散式版本控制系統), 所以程式碼可以用 "hg clone http://http://code.nsnam.org/ns-3-dev/" 抓下來. 預設的編譯程式是一般比較少聽過的 scons, 而在版本發佈規劃中不久就要以另一套 waf 來取代原本的 scons. scons 跟 waf 都是 Python 版的 "better Make" 程式. 總之原本 Makefile 要用 shell script 寫的地方,都改用 python script 來撰寫,可讀性較佳之外還可以用到 Python 語言的所有功能.

就 NS-3 模組本身而言,NS-3 去掉了 NS-2 中 討人厭的 使用 otcl 描述模型的方式,改成直接用 C++ 描述之後,安裝上簡單了不少,也不用多學一門沒啥用途的語言. C++ 讓多數基本網路元件可以重用,像以前各個模組會 "綁版本" 的情形應可降低很多.

目前還在開發中的 Python Binding 讓 網路模型也可以用 Python 描述, 晚上編譯完還沒意識到如何使用 Python 版。不過編好的 C++ 版一執行就跑出熟悉的 .tr 檔還是蠻有親切感的.

目前 NS-3 的核心網路元件還不多 (不過 node 終於可以有真的 IP 位址了 XD), 範例較少是比較可惜的。看看這情形要多久才能改善囉.

· 11 min read

相信在做網頁開發時不少人被表單處理困擾著, cherrypy 的網頁表單處理已經很簡單了, 而 TurboGears 更為我們帶來了 widget (網頁元件) 這個概念. 透過 widget 能簡單地完成產生表單,欄位驗證,重用表單等等仔細思考起來相當複雜的動作.

TurboGears 開發者們宣稱 widget 多麼好用,但是 widget 的說明文件卻相當缺乏.

那麼 widget 到底是什麼東西哩?

widget 是什麼

widget 用中文表達簡而言之就是 "網頁元件", TurboGears widget 的功能就是讓使用者重用所有網頁元件.

那麼網頁元件是什麼?網頁元件就是網頁的構成元素.

古代希臘先哲柏拉圖認為風,火,水,土是構成世界的四大元素。所有的物質最終都可以拆解成這四個元素.

而在網頁的世界裡,HTML, 表單 (Form), CSS, Javascript 則是網頁的四大構成元素.(註) 多數的網頁都可以由這四個元素組合產生.

Widget 表單元件

Widget 表單屬於 Widget 的一個重要分支。由以下的基本網頁元件組成:

* 表單欄位元件 (Field) — 等同於 HTML 表單欄位的基本元素, 如文字欄位 [input type="text"] 文字區塊欄位 (textarea) 等等. 用來產生基本的表單欄位.
* 表單欄位列表元件 (WidgetList) - 用來有機地組合表單欄位元件, 產生欄位列表, 提供表單元件使用.
* 表單元件(Form) — 表單欄位, 驗證資訊, 處理方式(post 或 get), 處理函式 (URI) 的集合. 可使用現有的驗證功能 validators.Schema 來做表單驗證.

除了基本的表單欄位元件,TurboGears 也透過 widget 提供了一些進階的表單欄位元件例如跳頁選單 (表單 + Javascript), 語法高亮 (HTML+CSS+Javascript), 標籤頁 (HTML+Javascript) 等元件,這些高級元件 (Rich Element) 也都是由這些網頁中最常見的基本元素所組成.

透過 widget 你可以自己建造自己的網頁元件,也可以透過 python 的擴充機制,很容易使用 easy_install 命令取得其他人共享出來的各種元件.

在使用高級元件之前,我們回到基本面上,先來看看如何用 widget 處理表單.

用 widget 產生表單欄位

你可以在互動式直譯器 (interactive interpreter) 裡試驗 TurboGears widget.

產生 TextField

>>> # TextField
>>> from turbogears.widgets import *
>>> Field = TextField(label='Main Menu')
>>> Field.render()
'<input id="widget" class="textfield" name="widget" type="text">'

產生 TextArea

>>> # TextArea
>>> Field2 = TextArea(label="Description", attrs=dict(rows=3, cols=60))
>>> Field2 = TextArea(label="Description",
... attrs=dict(rows=3, cols=60))
...
>>> Field2.render()
'<textarea rows="3" cols="60" class="textarea" name="widget" id="widget"></textarea>'
>>>

在 Python 互動式直譯器裡你可以看到用 TurboGears widget 產生一個表單欄位並不困難.

用 widget 產生跳頁選單

我們再來看如何用 widget 產生跳頁選單

跳頁選單適用於諸如 "選擇使用的語言" 等等情況, 可以在使用者選擇後自動跳至對應的網頁.

首先,我們先看看如何產生一般的網頁選單

>>> # SingleSelect Field
>>> Field3 = SingleSelectField(label="Author",
... options=[(1, "fred"), (2, "Joe")])
...
>>> Field3.render()
'<select class="singleselectfield" name="widget" id="widget"> <option value="1">fred</option><option value="2">Joe</option></select>'
>>>

到現在為止,我們可以確認產生一般網頁選單的方式與前面生成簡單文字欄位的方式完全一致.

我們接著來看看如何產生跳頁選單.

>>> # JumpMenu
>>> from turbogears.widgets import *
>>> Form = JumpMenu('Main Menu',options = [
... ('/createNewBatch', 'Create New Batch'),])
...
>>> Form.render()
'<select class="jumpmenu" onchange="TG_jumpMenu(\'parent\',this,0)" id="Main Menu" name="Main Menu"> <option value="/createNewBatch">Create New Batch</option></select>'
>>>

恩,產生跳頁選單跟產生一般網頁選單的使用方式並無二致。也同樣是這麼容易.

跳頁選單無法在 Python 互動式直譯器中完全表現, 因為在實際使用時,跳頁選單元件除了會產生這段 HTML 表單外, 嵌入 turbogears 網頁樣板時網頁元件還會自動嵌入相應的 javascript.

等你熟悉了 Turbogears 之後, 透過 widget, 即使是很複雜的 javascript 元件 (如所見即所得網頁介面編輯器), 你也不必擔心要導入哪些 Javascript library 等瑣事,透過網頁元件的分享,你可以直接透過 easy_install 命令即裝即用別人寫好的網頁元件。然後把時間用在自己網站內容的開發上.

用 widget 產生表單

前面已經講完用 widget 產生表單 "欄位" 了。然而一個表單除了基本的各個欄位之外, 還包含了一些其他元素。例如如何組織欄位,指定上傳方式 (GET/POST), 指定處理動作 (action) 等等.

TurboGears 裡已包含了數種預設表單欄位的格式。而其中最常見的就是 TableForm 了.

用 widget 組織表單欄位

可以透過 WidgetsList 來組織表單欄位.

>>> class BookFields(WidgetsList):
... title = TextField(label="Title")
... description = TextArea(label="Description")
...
>>> BookFields()
[TextField(name='title', convert=True, field_class='textfield', attrs={}, css_classes=[]), TextArea(name='description', convert=True, rows=7, cols=50, attrs={}, css_classes=[], field_class='textarea')]

我們已經組織起了兩個文字欄位,通過最後一行可以發現 WidgetsList 其實只是協助我們產生了一個表單欄位元件的列表. 接下來我們就要把這個欄位列表放進表單裡.

>>> class BookForm(TableForm):
... #name="Book"
... fields = BookFields()
... #validator = BookSchema()
... #method="post"
... submit_text = "Create"
...
>>> BookForm()
BookForm(name='form', submit_text='Create', convert=True, table_attrs={}, form_attrs={}, action=None, disabled_fields=set([]), method='post')
>>> BookForm().render()
'.form method="post" class="tableform" name="form".
......略......
./form.

基本上這產生的就是相當完整的表單了....

等等!~~想必你要大聲質疑:我的 "action" 呢???換句話說,我怎麼指定處理這個表單的 url 呢?

widget 與樣板合作

恩,好問題。你可以直接在宣告時就將 action 的值傳給 widget, 也可以在樣板 render 時再傳入。一般我習慣習慣在表單最終產生時 (樣板 render 時) 再指明.

例如這樣

在 controllers.py 中加入

model_form = BookForm() # 事先宣告好在重用時不用多次呼叫

產生實際表單頁面

@expose("template.new")
def new(self, **kw):
return dict(form = model_form)

在 "new.kid" 樣板中加入這一行

${form(action='save')}

當然有了處理這個表單的 url , 也需要在 controllers.py 中加入一個處理 "save" 這個處理表單資料的 method

@expose()
def save(self, id=None, **kw):
....

前面講起來好像花了不少篇幅,但其實看完程式後你會發現使用 widget 程式邏輯變得出乎意料之外的清晰. http://docs.turbogears.org/1.0/CRUDTemplate

用 widget 驗證表單欄位

驗證表單欄位其實只要在 TableForm 中傳入 validator 參數即可

>>> class BookForm(TableForm):
... fields = BookFields()
... validator = BookSchema()
... submit_text = "Create"
...
>>> BookForm().render()
.....略....

你可以使用 formencode 模組所提供的 "Schema" 完成任何複雜的表單驗證程序. 從比較基本的輸入字數長短 / 類型驗證,到多欄位密碼確認等都可以簡單地達成. (Turbogears 將 formencode 的 Schema 包裝成 validators.Schema)

>>> from turbogears import validators
>>> class BookSchema(validators.Schema):
... title = validators.String(not_empty=True, max=30)
... description = validators.String()
...
>>> BookSchema()
<bookschema object="" 114="" chained_validators="[]" fields="{'description':" title="" pre_validators="[]">
>>>

上一節中我們在 controllers.py 裡定義了

model_form = BookForm()

現在我們在做表單驗證時也可以用的上.

用法是簡單地在 "save" 這個 method 上加上 @validate (model_form) 裝飾。表示要使用 model_form 表單元件所附的表單驗證元件.

而要順便將輸入錯誤的訊息產生在表單上的話,只要再加入 @error_handler (new) 裝飾, 表示如果有錯誤就跳轉到 new 這個 method (我們的表單頁) 處理.

@validate(model_form)
@error_handler(new)
@expose()
def save(self, id=None, **kw):
....

widget 還可以幹什麼

widget 可以讓你用最 Pythonic 的方式表現網頁表單,也可以簡化提供不同 AJAX 函式庫的支援.

你覺得網頁元件能幹什麼,Turbogears widget 就可以幫助你幹什麼.

怎麼知道有哪些 widget

Turbogears 的網頁工具箱 toolbox 中有網頁元件瀏覽器 (widget browser). 使用 $tg-admin toolbox 命令啟動網頁工具箱就會看到網頁元件瀏覽器. 在網頁元件瀏覽器中你可以找到所有內建與外掛的網頁元件.

外掛的網頁元件 (widget plugin) 可以在 cogbin (http://www.turbogears.org/cogbin/) 找到.

註:嚴格說來,"表單" 其實是屬於 HTML 的一部分. 所以也可以說網頁的三大基本組成元素是 HTML, CSS, Javascript.

TurboGears widget 實現表單的方式也是組合這三大基本組成元素.

然而因為表單的使用與其他 HTML 元素的使用有較大差別. 在說明時獨立出來更易於理解.

· One min read

TurboGears 的開發哲學有三:

1. Keep simple things simple and complex things possible 讓簡單的事情維持簡單,並讓複雜的事情變得可辦到

2. Give defaults while you give choices 提供選擇時一並提供預設值.

3. Give choices while the one obvious way depends 當莫衷一是時就提供選擇.

· One min read

以前已經有些人研究過 Python 原始碼.

python 源码剖析

python 源码分析

python 源码分析 中有列出 Python 語法分析的機制。回顧一下 cPython 的整個處理流程:

1. PyTokenizer 進行詞法分析,把源程序分解為 Token

2. PyParser 根據 Token 創建 CST

3. CST 被轉換為 AST

4. AST 被編譯為字節碼 ByteCode

5. 執行字節碼

這個流程是直譯器 Interpreter 的流程. 大體也可以套用在 pypy 的 Python 直譯器上.

PyPy - Goals and Architecture Overview (pypy 架構) 一文中講到 pypy 有兩大構成部份, 其一就是 Python Interpreter (直譯器), 其二則是 Translation Framework (轉譯器).

.... 寫好的被 Ctrl+Z 吃掉了.... 待補... Orz