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++的差異。所以我說懂得一種程式語言不是一兩個月內的事情,如果一兩個月內可以學會一種語言,大概就是指語法之類的吧!不然此人必定對程式語言設計本身有極高的素養,才可能在短時間內達成,不然大多數人應該只能花更長的時間理解一個程式語言的內含吧