2011年10月29日 星期六

python list排序

以下是sort的具體實例。
實例1:
>>>L = [2,3,1,4]
>>>L.sort()
>>>L
>>>[1,2,3,4]
實例2:
>>>L = [2,3,1,4]
>>>L.sort(reverse=True)
>>>L
>>>[4,3,2,1]
實例3:
>>>L = [('b',2),('a',1),('c',3),('d',4)]
>>>L.sort(cmp=lambda x,y:cmp(x[1],y[1]))
>>>L
>>>[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
實例4:
>>>L = [('b',2),('a',1),('c',3),('d',4)]
>>>L.sort(key=lambda x:x[1])
>>>L
>>>[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
實例5:
>>>L = [('b',2),('a',1),('c',3),('d',4)]
>>>import operator
>>>L.sort(key=operator.itemgetter(1))
>>>L
>>>[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
實例6:(DSU方法:Decorate-Sort-Undercorate)
>>>L = [('b',2),('a',1),('c',3),('d',4)]
>>>A = [(x[1],i,x) for i,x in enumerate(L)] #i can confirm the stable sort
>>>A.sort()
>>>L = [s[2] for s in A]
>>>L
>>>[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
以上給出了6中對List排序的方法,其中實例3.4.5.6能起到對以List item中的某一項
為比較關鍵字進行排序.
效率比較:
cmp < DSU < key
通過實驗比較,方法3比方法6要慢,方法6比方法4要慢,方法4和方法5基本相當
多關鍵字比較排序:
實例7:
>>>L = [('d',2),('a',4),('b',3),('c',2)]
>>> L.sort(key=lambda x:x[1])
>>> L
>>>[('d', 2), ('c', 2), ('b', 3), ('a', 4)]
我們看到,此時排序過的L是僅僅按照第二個關鍵字來排的,如果我們想用第二個關鍵字
排過序後再用第一個關鍵字進行排序呢?有兩種方法
實例8:
>>> L = [('d',2),('a',4),('b',3),('c',2)]
>>> L.sort(key=lambda x:(x[1],x[0]))
>>> L
>>>[('c', 2), ('d', 2), ('b', 3), ('a', 4)]
實例9:
>>> L = [('d',2),('a',4),('b',3),('c',2)]
>>> L.sort(key=operator.itemgetter(1,0))
>>> L
>>>[('c', 2), ('d', 2), ('b', 3), ('a', 4)]
為什麼實例8能夠工作呢?原因在於tuple是的比較從左到右之一比較的,比較完第一個,如果
相等,比較第二個

2011年5月2日 星期一

python 3的特性

http://www.ibm.com/developerworks/cn/linux/l-python3-1/
http://www.ibm.com/developerworks/cn/linux/l-python3-2/
老實說,即使到了現在,很多開發的程式還是停留在2.6或者2.7,很多開發者不願意移植,事實上這種轉移比商業軟體還久,所以才在這裡再重複了一個參考連結

2011年4月20日 星期三

Collection內的方法

身為collection的class有許多方法,其實是用來支援某些運算子的
__contains__(self,x) # x in collection
__delitem__(self,k) #del y[k]
__getitem__(self,k) #y[k]
__setitem__(self,k,v)#y[k]=v
__iter__(self) # 回傳iterator
__len__(self) #len(y)
__reversed__(self) #revsersed(y)
理解了這些類似operator overloading的東西之後,大致上對於python就比較能理解背後運作的原理了

2011年4月18日 星期一

Python -- property

先來談談property,我第一次看到類似property的東西是在delphi上面,他讓programmer可以作一些存取控制,但是有如同直接存取變數一樣
接下來java bean也再看到了一次這樣的東西,很不幸的這次是一堆getter跟setter,也就是你必須在屬性前面加上getArea, setArea等等,即使他只是單純的access一個變數,如果沒有IDE的幫助,這簡直是一個惡夢

python上面的作法是使用decorator,也就是用@property這個語法,他支援四種引數,getter, setter,deleter, docstring
可以想像得到,如果使用一個自動計算面積的circle class,如果希望直接取得屬性,如circle.area,你可以使用
@property
def area(self):
return math.pi*(self.radius**2)
如果是setter則是
@property
def radius(self):
return self.__radius
@property.setter
def radius(self,radius):
assert radius>0, "radius must be non zero and non-negative!"
self.__radius=radius
由於property的作用,不用擔心radius這個屬性會產生名稱衝突,其實一使用property的時候,四個屬性等於全部被啟用,但是預設由python接手沒寫得東西,但是python就是啥都不做XD

回過頭來說到屬性,很多時候真的覺得他只是一個candy,也就是甜頭啦,如果說老是充斥這種東西,方便性取代了程式的易讀性以及可能會忽略掉一些程式的邏輯
當一個programmer讀到某個function,他會心裡開始描述這個function的運作方式,他也的確知道這個function出現的時機,對於理解程式是有正面的幫助的,但是因為property的作用,使用者可能會無法領悟到這部份的事實
接下來另外一點干擾是邏輯性,當使用變數的時候,你並不會預期他會丟出一個例外,可是這對很多function來說是很正常的事情,甚至是必要的,在這樣的狀況下,很多使用者會忽略這個部份

老實說,綜觀這麼多程式,我很少可以找到一個絕對的必要性,必須使用property,如果是簡單的access,大可讓使用者直接access,如果必須作一些boundary控制,我覺得應該使用function模式,讓使用者在使用的時候有所警惕

另外其實decorator在python裡面有其他神奇的作用,java也是,decorator感覺已經有點變成語法了orz,另外一個討厭decorator的地方是,感覺他很不像"語法",像是註解,但是又有程式的"邏輯"/"作用"在,decorator其他部份以後有時間再寫

2011年4月16日 星期六

Python心得

本來是打算學習ruby,但是後來傾向python,但是因為本身也不是對任一程式語言沒有接觸過,所以並不打算從頭到尾介紹一次某種程式語言,所以雖然這個網誌算是我的筆記,但也不是適合完全的新手來看,應該比較打算朝向tip or cookbook的方式去紀錄
再者另外一點我覺得很重要的是,我認為python並不適合一個完全不懂程式語言的人去使用,雖然本身它提供了很多syntax candy,讓一些使用者似乎可以很快的進入狀況,但是後面的原理卻是大量的OOP以及泛型。
換句煥說,當一個新手可能很快的進入狀況之後便碰到了一個玻璃的天花板,本身要去學會其他programming的準則或者原理之後才能更進一步。
最後,我認為python很適合拿來實作一些想法,讓使用者更專心在他想驗證或者實作的小功能上,而不是花太多的時間在debug與tuning上面;但是如果是以效能為主,python可能就無法勝任,比方說繁雜的科學計算,當然有lib可以做到這一點,但是他底層是C++ or fortran,主要是因為python的執行效能不彰,python的運算速度的確是慢於C++/java之類的。反過來說,如果是ㄧ些管理功能上的小程式,我倒是覺得python開發遠遠快於C++/java

Python -- OO

Python雖然不全面支援OO所有的特色,並不表示他無法做OO設計,同時也不表示OO不好,雖然我在寫小程式(1k lines以下)覺得Python開發速度很快,但也不表示OO不適用
在許多OOP裡面的overloading以及access control在Python並不支援,大多數Python的的類別屬性是公開的,對於存取的限制仰賴於programmer的素養(依循一定的規則)以及一些decorator的幫助。
另外由於python並不強調型態的重要性,他使用的是duck typing,也就是如果一個型態表現類似某一種型態的特性,你就可以把它當作該型態使用,比方說某隻鳥類似鴨子,你就可以把這隻鳥當作鴨子,可能他只是會呱呱叫,然後會飛短短的距離,python就當他是鴨子,可是根本的型態可能不是鴨子。
python跟java一樣,預設有一個class Object,所有新的class都繼承自這個Object,其中有許多重要的方法,一般python內定的方法使用__(雙底線/double under line)開頭。__str__()傳回一個該物件的字串描述,很類似java的toString();另外有一個__repr__()他回傳該物件的字串,如果執行該字串就可以得到一個一模一樣的物件;預設中python會讓所有的物件可以hash,依賴的是object id,但是一旦改寫了__eq__()方法之後,這個物件就不再是可hash,也就是無法放入set或者dict型態內了。

2011年4月15日 星期五

Python -- Iterable

在python裡面有個重要的類別或者說觀念,就是iterable,何謂iterable?也就是本身要提供__iter__()這個方法,他會回傳一個iterator,每個iterator都有個__next__()的方法來取得下個元素
iterator大量使用在for迴圈跟list/set comprenhesion,對於sequence,iterator將會參考到sequence object,然後在__next__()呼叫sequence.__getitem(index),iterator本身只要維護那個index,就可以從0走到len(sequence),逐一取得sequence裡面的元素
而對於類似dict或者set這類的資料型態,就無法保證取出的順序,更有趣的是dict是屬於key/value的pair,那麼__iter__()回傳的是啥?答案是他是一個由dict.keys()產生的iterator,也就是這個iterator每次呼叫__next__()取回的是下一個key
iterator骨子裡面都是包含資料的物件嗎?答案是有例外的,比方說range所產生的iterator,其實他是一個特殊的yeild關鍵字所產生的iterator,他本身只有一個變數,類似C裡面的static,好處是可以這樣的一個物件不用佔用大量的空間,過去range回傳是一個tuple or list,也就是裡面每個元素都是佔有實際記憶體空間的

回頭來看過去for等等的語法格式
for variable in iterable:
suite
list/set的comprehension格式
[item for item in iterable]
這樣就比較瞭解,我們可以把何種物件變成list或者如何用for迴圈去走訪一個物件裡面的元素

另外有些常用的運算如all(), any(), max(), min(), sort(), sum()等等運算可以作用在iterator之上

其實python裡面還有許多方法是對應到operator overloading跟value的assign,瞭解這些方法,會讓programmer更加瞭解python裡面運作的方式,進而寫出更簡潔的code。

同時如果理解許多本來C/C++並不支援的機制,如decorator,就會更加瞭解python與C/C++的差異。所以我說懂得一種程式語言不是一兩個月內的事情,如果一兩個月內可以學會一種語言,大概就是指語法之類的吧!不然此人必定對程式語言設計本身有極高的素養,才可能在短時間內達成,不然大多數人應該只能花更長的時間理解一個程式語言的內含吧

2011年4月13日 星期三

邏輯、Logic、邏輯、Logic、邏輯、Logic

想來以前還真的沒腦袋XD如何說沒腦袋呢?也就是對寫出來的東西並沒有經過安排,好類似家說的spaghetti code。設計程式好比在建築一般,如果只是不要倒塌,或者設計出一個功能有的系統,就會做得很類似堆砌的工作,好比一個房子建好了,該有的功能都有了,但是用起來就是不順手,外觀就是不好看。

pattern一詞來自建築業,其實當設計師在設計房屋的時候不只考慮到單一的問題,比方說洗手間需要通風良好的地方這個pattern,如果說單單為了這個理由隨便把它放在玄關附近,那整個房子就相當的不倫不類了,一進門就看到洗手間的房子,訪客及主人一進門就聞到洗手間的味道,還真的是不好的印象。所以設計師可能就要考慮把洗手間挪到其他的地方,讓一個問題解決的pattern不會影響到其他的pattern才是整體設計的最高指標。雖然有時無法完全排除,但是總要找到一個相對較好的解決方案。

一個房子該有的功能有了,是最基本的要求,相對於此,整體完整性的設計是更高的標竿,然而整體後面支撐的就是邏輯性、合理性。我過去總是沒有腦袋的把所有問題解決就好,從來沒有思考過如何讓整體得到更好的解決,因為我很少去review自己寫過的東西。

自從看到約耳的文章,認為把code丟掉重新撰寫是一個浪費時間的行為,跟某個日本作者提到,寫下來的文章可以不斷地修改,精煉其中的語文,除了責任感之外更是一種工藝的表現,讓我十分汗顏,我想到我過去丟掉過無數的code,很少對自己的文章重新檢視,以後得好好地加強這個部分,這樣才能做一個好的designer而不是單單的programmer

選擇Python

Python在國內完全比不上國外的發展,幾乎大多數的程式語言不是主流的C#/C++/C跟java就是PHP(web),在不然就是VB,國內的Python資源幾乎是非常缺乏

一開始接觸python是想要在ruby與其中挑選一個,一個script語言,我的要求是可以快速驗證一些我想處理的資料跟想法,而一開始挑選python跟ruby老實說是有點被"騙"了XD,就是網路上那種十分鐘快速建立blogger,我很好奇,如何在十分鐘內完成blogger的coding??結果就是天下沒有白吃的午餐

那麼為何會放棄ruby而選python??因為接觸了rubby一陣子之後,發現他是蠻物件導向的語言,我選擇script就是想輕裝上陣,如果還要考慮物件導向,那麼不就很累人了
難道是OO不好嗎?不是這麼說,瞭解OO, pattern這類的東西,大多是把本來coding的複雜度,轉換為關係的複雜度,只要瞭解到了,你付出了怎樣的成本,獲得怎樣的好處,適度使用OO,也是可以相當的愉快的

python並沒有很完整的支援物件導向,他使用了其他的方式來支援,也就是不是原生的支援物件導向,這點使得他在開發物件導向的程式會受到好些限制,不過同時也換來了相當多的彈性。另外一點不同的是python更強調泛型演算法的部份,他的各種容器幾乎都以泛型的設計為主

我想不少programmer跟我有一樣的"幻覺",認為只要熟悉C/C++之後,其他程式語言上手就很快了,我想這只是語法部分,至於語言中間設計的方式可能要花上三到六個月才能體會出來。如果一個C++換到java很快會發現,他開發速度不如一個java老鳥的人,他或許會解釋為對java library的不熟悉。可是很多不只是java library的問題,比方說code的簡潔程度,code撰寫方式,很多本身是依賴於程式的特性的,更貼近的一點的,比方java有seriable介面來處理物件轉成檔案的問題,可是C++並沒有,這時候C++的programmer可能會自己處理,這並不是表示C++使用者做不出這樣的功能,換了程式語言之後兩者之間生產力的問題。

語言的特色影響了熟悉他與否的programmer生產力,倒不是本身programmer能力的限制,在我慢慢深入python之後,我覺得我會用的程式語言"愈來愈少",因為本身背後設計的原理我能理解大多數的還真的不多!!