初識Python
第一次聽說Python已經(jīng)是三四年前的事情了七蜘。當(dāng)時是用C#幫人處理了一個有向圖的小代碼霉囚。對方問捕仔,用什么寫的,是Python嘛盈罐。我才知道還有Python這么個東西榜跌。當(dāng)時只知道這是一個跨平臺的腳本語言。隨后曾在回家的火車上看過一點點盅粪,但一直沒有實實在在的使用過钓葫。天生的對腳本語言不感興趣。
用上Python
最近在幫助一個朋友搞輸入法的算法票顾,需要在Python上進行算法測試瓤逼。同時,也想著库物,以后盡量把科學(xué)計算的工具從原來可能只有我才用的C#轉(zhuǎn)到比較通用的Python上。于是贷帮,匆匆忙忙的看了幾天就直接上手了戚揭。用了一個多月,感嘆Python確實在某些方面是很神奇的撵枢。比如民晒,Python可以用a, b = b, a來交換a和b的值。
實用的數(shù)據(jù)結(jié)構(gòu)
應(yīng)該是因為功能定位不同锄禽,Python和其他語言的大部分教程不同潜必。Python一上來并不是講int、float沃但、double磁滚、string和數(shù)組等基本類型,而是介紹list宵晚,turple和dictionary(還有一個可能不太常用的set結(jié)構(gòu))這些數(shù)據(jù)結(jié)構(gòu)垂攘。在c#中,list要用ArrayList淤刃,turple相當(dāng)于結(jié)構(gòu)體晒他,dictionary相當(dāng)于HashTable,三個都已經(jīng)算是相對高級的應(yīng)用了逸贾,至少是需要增加Using才能使用的(結(jié)構(gòu)體不是)陨仅。尤其是字典類型津滞,如果不是萬不得以,好像基本不會使用HashTable灼伤,更別說的字典中套字典了触徐。而在Python中,不僅把這個三種實用的數(shù)據(jù)結(jié)構(gòu)做為基礎(chǔ)直接使用饺蔑,而且還經(jīng)常聯(lián)合使用锌介。對于純粹的數(shù)據(jù)處理和計算來說,大縮短了代碼編寫的時間猾警。能靈活熟悉的使用這三種數(shù)據(jù)結(jié)構(gòu)孔祸,Python就基本上算是初步掌握了。
有趣的下標(biāo)引用
list发皿,turple和dictionary都是數(shù)據(jù)的存儲結(jié)構(gòu)崔慧。引用一串?dāng)?shù)據(jù)中的某一個或某幾個是最常用操作。和C#一樣穴墅,Python也是用[n]來引用惶室,但在操作上Python有許多獨特的邏輯。比如玄货,Python的引用是可以用負(fù)數(shù)的皇钞。
data = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
data[0] #取第一個元素,結(jié)果為['Monday']
data[-1] #取最后一個元素松捉,結(jié)果為['Sunday']
data[:5] #從開頭取夹界,取到5號個元素之前,結(jié)果為['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
data[4:] #從第4個元素取到最后隘世,結(jié)果為['Friday', 'Saturday', 'Sunday']
data[1:2] #從第1號元素取可柿,取到2號元素之前,結(jié)果為['Tuesday']
data[3:-2] #從3號元素取丙者,取到倒數(shù)第2個元素之前复斥,結(jié)果為['Thursday', 'Friday']
甚至你還可以這樣把所有奇數(shù)位或偶數(shù)位的取出來,生成一個新的list:
data[::2] #結(jié)果為['Monday', 'Wednesday', 'Friday', 'Sunday']
data[1::2] #結(jié)果為['Tuesday', 'Thursday', 'Saturday']
雖然C#也可以用Substring方法實現(xiàn)字符串的截取械媒,但使用上就不如Python來的直觀目锭,而且該方法也僅限到普通的字符串。
獨特循環(huán)方式
Python中的循環(huán)全是類似于C#中foreach的遍歷式循環(huán)滥沫,如遍歷鏈表侣集、元組或字典。
for item in data_list:
print(item)
for item in data_turple:
print(item)
for key in data_dic:
print(key, data_dic[key])
當(dāng)然兰绣,對于字典類型的普遍世分,由于很多時候會可能會改變字典的內(nèi)容,如刪除某些鍵值缀辩,所以通常是遍歷字典鍵的鏈表:
for key in list(data_dic.keys()):
...
那么臭埋,如果確實是要計算一個從1加到100的循環(huán)又該怎么辦呢踪央。在Python中,需要用range內(nèi)嵌構(gòu)建一個鏈表來實現(xiàn):
for item in range(1,101):
...
所以瓢阴,Python中通常不會使用i, j, k這種循環(huán)變量名畅蹂。
Python的循環(huán)還能使用一個特別的zip組合,可以把兩個鏈表組合成一個元組的鏈表荣恐,然后把元組中的元素分別賦值給不同的變量進行遍歷液斜。至于有什么用,那就要看具體的需求了叠穆。在保存輸入法的詞庫數(shù)據(jù)時少漆,為了節(jié)省空間,把同一個拼音的重碼和對應(yīng)的權(quán)重保存在了同一條記錄中硼被,并用‘|’進行了分隔示损。那么,獲取某一個詞的概率嚷硫,或者是某一個音對應(yīng)所有詞的權(quán)重就可以這樣寫:
#比如检访,取出的youji對應(yīng)的重碼概率保存在了result中
result = '郵寄|0.3|有機|0.2|游擊|0.2|游記|0.1'
result_list = result.split('|') #將結(jié)果轉(zhuǎn)為list結(jié)構(gòu)
for word, weight in zip(result_list[::2], result_list[1::2]):
print(word, weight)
zip實際上是先把兩個list打包成了一個成員是元組的list,然后再遍歷元組仔掸,分別把元組的元素賦值給word和weight脆贵。如果用C#,就等同于:
for(i=0;i<=result_list.count-1;i++){
word = result[i];
weight = result[i+1];
i++;
Console.writeline(word.tostring() + weight.tostring());
}
雖然看上去好像也不是特別麻煩起暮,但邏輯上還是Python的更易懂一些丹禀。
看不明白的排序
排序是最常用的算法之一,大部分語言也都內(nèi)置了排序的方法或函數(shù)鞋怀。但是,主要都是針對基本類型的持搜。如果要對一個結(jié)構(gòu)體密似,或者類進行排序,其代碼量也不算少葫盼。比如残腌,前段時間在處理詞頻信息時,需要按詞頻進行排序贫导。如果用兩個鏈表分別保存「詞」和「頻度」抛猫,那在對「頻度」時,就不能同步調(diào)整「詞」的順序孩灯。因此闺金,必須把「詞」和「頻度」放在一個結(jié)構(gòu)體中,對結(jié)構(gòu)體進行排序峰档。在C#中可以這樣實現(xiàn):
//先需要聲明一個結(jié)構(gòu)體败匹,把所有需要同時排序的元素放在一起
//類似于Python形成一個元組
struct Unite{
string word;
int count;
}
//還需要聲明一個排序比較的方法寨昙,比較的元素類型為聲明的結(jié)構(gòu)體
//在方法中明確排序時的比較元素,及是正序還是逆序
private static int CompareByCountDes(Unite x, Unite y){
if (y.m_count - x.m_count > 0) return 1;
else if (y.m_count - x.m_count < 0) return -1;
else return string.Compare(x.m_word, y.m_word);
}
//然后才能用Sort方法對結(jié)構(gòu)體進行排序
//Unite_List是一個元素為結(jié)構(gòu)體Unite的鏈表掀亩,即List
Unite_List.Sort(CompareByCountDes);
然而舔哪,在Python中,對于元素是元組的鏈表槽棍,其排序用一行代碼就可以完成:
sorted(Unite_List, key=lambda item:float(item[1]), reverse=True)
其中捉蚤,Unite_List中的元素為(word, count)形式的元組,key后面指定的是排序的依據(jù)元素炼七,lambda是一個內(nèi)嵌的小函數(shù)(到現(xiàn)在也不是特別明白)缆巧。但至少明白,是按item[1]進行排序特石,即按count進行排序盅蝗,如果要按word排序,可指定為item[0]姆蘸。最后的參數(shù)reverse如果為「真」墩莫,則為逆序,默認(rèn)值為假逞敷,是正序狂秦。
雖然,排序的內(nèi)部過程大概都是要走兩層循環(huán)推捐,但在代碼上Python則更容易一些裂问。
簡單的文件和數(shù)據(jù)操作
把運算的數(shù)據(jù)保存在文件和數(shù)據(jù)庫,或者從文件或數(shù)據(jù)庫中讀取數(shù)據(jù)牛柒,也是常見的操作堪簿。C#中讀取文本文件,需要聲明一個FileStream用來指定文件路徑和打開方式皮壁,即「讀」或「寫」或「追加」等椭更。然后,使用StreamReader讀取文件蛾魄。讀取的過程一般通過while循環(huán)來完成虑瀑。文件讀寫之后,還建議對這兩個對象執(zhí)行Close操作滴须。
但Python中舌狗,只需要指定一個文件讀取變量就行:
FileRead = open('read.txt', 'r', encoding='utf-8')
content = FileRead.readlines()
for line in content:
print(line)
FileRead.close()
如果使用with結(jié)構(gòu),還可以把close省略掉扔水。
對于數(shù)據(jù)庫痛侍,也可以省掉open和close的過程,也不用像C#那樣去聲明一個Connection和Command對象魔市。對于sqlite這種輕型的數(shù)據(jù)庫恋日,只需要提供數(shù)據(jù)庫文件的路徑膀篮,就可以直接執(zhí)行sql語句:
conn = sqlite3.connect("sqlite.db")
conn.execute('create table ...')
conn.execute('insert into ...')
conn.execute('delete from ...')
conn.execute('update ...')
# 對于查詢結(jié)果,可以通過遍歷的形式讀取
result = conn.execute('select id, name from people')
for row in result: #遍歷查詢結(jié)果的第一條記錄
print(row[0], row[1]) #row[0]對應(yīng)id岂膳,row[1]對應(yīng)name
當(dāng)然誓竿,Python主要用于實現(xiàn)數(shù)據(jù)處理,所以Python一般多用在后臺谈截,前端的UI處理還需要借助其他工具筷屡。