2011/05/22

The Python Paradox

This is a zh-tw translation of The Python Paradox by Paul Graham.

在某次演講中,我的話語惹毛不少人,那段話是這樣說的 -「使用 Python 的專案,會比 Java 的專案,容易吸引到更聰明的程式人員。」

我可沒說 Java 程式員是笨的,那句話的焦點在於 Python 程式員是聰明的。學習一個新的程式語言,需要花費不少工夫,因此,人們不會為了混口飯吃,而去學 Python,那些學 Python 的程式員,是基於對編程的熱愛,而且他們對已知的語言都感到不滿意。

這類的程式員,應該是公司想要雇用的。由於找不到好的形容詞,我姑且稱這種現象是 Python 的弔詭 - 如果公司的軟體專案使用密教式的語言來開發,他們會雇用到較好的程式員,因為這樣的條件會吸引那些願意學這類語言的好手。對程式人員而言,下列的說法,更是無庸置疑:如果你想要找到好工作,該學的語言,必然不是那些只能混口飯吃的語言。

迄今,只有很少的公司夠聰明,能明白這樣的道理,不過,還有另一種演化趨勢,來自於那些最受程式員喜愛的公司,例如 Google,當他們要找 Java 工程師時,也會要求同時具備 Python 經驗。

我有個朋友,熟知所有廣被使用的語言,他手邊的專案,多數就用 Python 開發,而選用 Python 的最大原因,是程式碼看起來舒服。比較程式語言的選用條件時,這樣的理由聽起來可能好笑,但搭配下列的情境,這句話就不像鬧著玩了:動手編程時,你會花很多時間在讀程式碼,而不是寫程式碼。編修程式碼的過程,就像雕塑師在作品上捏塑泥巴的過程,如果語言讓程式碼變醜,嚴謹的程式員看了可會抓狂,就像糊成一團的泥巴,會讓雕塑師無法忍受一樣。

提到醜的程式碼,人們很容易想到 Perl,不過,Perl 表面上的醜,或是生硬語法所帶來的醜,並不是我想講的,錯誤概念所造成的醜,才是真的讓人無法接受的事。有時候 Perl 程式碼看起來像卡通人物幹譙時的一串符號,但有些情況下,Perl 在概念上比 Python 來得優異。

話說回來,這兩個語言仍然各自演化中,和 Ruby (Icon, Joy, J, Lisp, Smalltalk) 一樣,投身它們的程式員,都是熱愛編程的族群,而且是更有機會搞好編程的一群。

2011/05/14

Related Items and ReferenceField

預設的 ATContentType 提供 relatedItems 欄位,可以用來建立或指定關連項目,想在程式裡指定的話,可以參考下列的資訊:

>>> app.mysite['front-page'].setRelatedItems(app.mysite.news)
>>> app.mysite['front-page'].getRelatedItems() [<ATFolder at /mysite/news>]

setRelatedItems() 每次只接一個參數,因此後來接的參數,原則上就是蓋掉之前的設定值。想要清空內容的話,就是使用 setRelatedItems(''),想要指定多值,或是加入新值的話,可用串列的技巧:

>>> app.mysite['front-page'].setRelatedItems
  ([app.mysite.news,app.mysite.events])

還有個 getRawRelatedItems() 可以傳回 UID:

>>> app.mysite['front-page'].getRawRelatedItems()
['f8a2a96821f6e3df8dafd19d16b68fb2', '04b2e1267906691beccdff58dd861176']

可以試試 getRelatedItems() + UID() 是否跟 getRawRelatedItems() 結果是否相同。另外,在plone.app.layout/viewlets/content.py 裡的 ContentRelatedItems 程式碼片段,示範如何存取及顯示:

class ContentRelatedItems(ViewletBase):
    index = ViewPageTemplateFile("document_relateditems.pt")

    def related_items(self):
        context = aq_inner(self.context)
        res = ()
        if base_hasattr(context, 'getRawRelatedItems'):
            catalog = getToolByName(context, 'portal_catalog')
            related = context.getRawRelatedItems()
            if not related:
                return ()
            brains = catalog(UID=related)
            res = list(brains)
        return res

2011/05/12

Values for Archetypes Field and Widget

StringField 搭配 StringWidget 或 SelectionWidget 是最簡化的情況,儲存的資料是 string,如果 StringField 搭配 MultiSelectionWidget 或 InAndOutWidget,儲存的資料就是 list。前者的空值是 '',後者的空值是 [''],使用 page template 顯示時,就要額外處理它們的差異。例如:
<div tal:condition="context/myfield">
My Field:
<span metal:use-macro="python:context.widget('myfield', mode='view')" />
</div>
當資料是空的 string 時,整個 <div /> 並不會顯示,當資料是空的 list 時,還是會出現 My Field: [''] 之類的畫面。
一個簡單的處理方式是:
<div tal:condition="python:context.myfield != ['']">
My Field:
<span metal:use-macro="python:context.widget('myfield', mode='view')" />
</div>

2011/05/10

Couldn't find index page for 'PasteScript'

在 Plone 4.0.2 正常運作一段時間後,因為修改 src 目錄裡的自製模組,需要重新執行 bin/buildout,遇到錯誤訊息:
Download error: (-2, 'Name or service not known') -- Some packages may not be found!
Couldn't find index page for 'PasteScript' (maybe misspelled?)

distutils.errors.DistutilsError:
Could not find suitable distribution for Requirement.parse('PasteScript')
While:
Installing.
Processing develop directory '/home/marr/mysite/zinstance/src/my.package'.
檢查 my.package/setup.py 裡面有一行 setup_requires=["PasteScript"], 設定值,註解掉暫時有排除問題,但仍不清楚原理。
另外在 Problems running Buildout to install a them created with Paster 有類似的討論,或許會有正確解答的線索。