初识Python
第一次听说Python已经是三四年前的事情了。当时是用C#帮人处理了一个有向图的小代码。对方问,用什么写的,是Python嘛。我才知道还有Python这么个东西。当时只知道这是一个跨平台的脚本语言。随后曾在回家的火车上看过一点点,但一直没有实实在在的使用过。天生的对脚本语言不感兴趣。
用上Python
最近在帮助一个朋友搞输入法的算法,需要在Python上进行算法测试。同时,也想着,以后尽量把科学计算的工具从原来可能只有我才用的C#转到比较通用的Python上。于是,匆匆忙忙的看了几天就直接上手了。用了一个多月,感叹Python确实在某些方面是很神奇的。比如,Python可以用a, b = b, a来交换a和b的值。
实用的数据结构
应该是因为功能定位不同,Python和其他语言的大部分教程不同。Python一上来并不是讲int、float、double、string和数组等基本类型,而是介绍list,turple和dictionary(还有一个可能不太常用的set结构)这些数据结构。在c#中,list要用ArrayList,turple相当于结构体,dictionary相当于HashTable,三个都已经算是相对高级的应用了,至少是需要增加Using才能使用的(结构体不是)。尤其是字典类型,如果不是万不得以,好像基本不会使用HashTable,更别说的字典中套字典了。而在Python中,不仅把这个三种实用的数据结构做为基础直接使用,而且还经常联合使用。对于纯粹的数据处理和计算来说,大缩短了代码编写的时间。能灵活熟悉的使用这三种数据结构,Python就基本上算是初步掌握了。
有趣的下标引用
list,turple和dictionary都是数据的存储结构。引用一串数据中的某一个或某几个是最常用操作。和C#一样,Python也是用[n]来引用,但在操作上Python有许多独特的逻辑。比如,Python的引用是可以用负数的。
data = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
data[0] #取第一个元素,结果为['Monday']
data[-1] #取最后一个元素,结果为['Sunday']
data[:5] #从开头取,取到5号个元素之前,结果为['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
data[4:] #从第4个元素取到最后,结果为['Friday', 'Saturday', 'Sunday']
data[1:2] #从第1号元素取,取到2号元素之前,结果为['Tuesday']
data[3:-2] #从3号元素取,取到倒数第2个元素之前,结果为['Thursday', 'Friday']
甚至你还可以这样把所有奇数位或偶数位的取出来,生成一个新的list:
data[::2] #结果为['Monday', 'Wednesday', 'Friday', 'Sunday']
data[1::2] #结果为['Tuesday', 'Thursday', 'Saturday']
虽然C#也可以用Substring方法实现字符串的截取,但使用上就不如Python来的直观,而且该方法也仅限到普通的字符串。
独特循环方式
Python中的循环全是类似于C#中foreach的遍历式循环,如遍历链表、元组或字典。
for item in data_list:
print(item)
for item in data_turple:
print(item)
for key in data_dic:
print(key, data_dic[key])
当然,对于字典类型的普遍,由于很多时候会可能会改变字典的内容,如删除某些键值,所以通常是遍历字典键的链表:
for key in list(data_dic.keys()):
...
那么,如果确实是要计算一个从1加到100的循环又该怎么办呢。在Python中,需要用range内嵌构建一个链表来实现:
for item in range(1,101):
...
所以,Python中通常不会使用i, j, k这种循环变量名。
Python的循环还能使用一个特别的zip组合,可以把两个链表组合成一个元组的链表,然后把元组中的元素分别赋值给不同的变量进行遍历。至于有什么用,那就要看具体的需求了。在保存输入法的词库数据时,为了节省空间,把同一个拼音的重码和对应的权重保存在了同一条记录中,并用‘|’进行了分隔。那么,获取某一个词的概率,或者是某一个音对应所有词的权重就可以这样写:
#比如,取出的youji对应的重码概率保存在了result中
result = '邮寄|0.3|有机|0.2|游击|0.2|游记|0.1'
result_list = result.split('|') #将结果转为list结构
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的更易懂一些。
看不明白的排序
排序是最常用的算法之一,大部分语言也都内置了排序的方法或函数。但是,主要都是针对基本类型的。如果要对一个结构体,或者类进行排序,其代码量也不算少。比如,前段时间在处理词频信息时,需要按词频进行排序。如果用两个链表分别保存「词」和「频度」,那在对「频度」时,就不能同步调整「词」的顺序。因此,必须把「词」和「频度」放在一个结构体中,对结构体进行排序。在C#中可以这样实现:
//先需要声明一个结构体,把所有需要同时排序的元素放在一起
//类似于Python形成一个元组
struct Unite{
string word;
int count;
}
//还需要声明一个排序比较的方法,比较的元素类型为声明的结构体
//在方法中明确排序时的比较元素,及是正序还是逆序
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方法对结构体进行排序
//Unite_List是一个元素为结构体Unite的链表,即List
Unite_List.Sort(CompareByCountDes);
然而,在Python中,对于元素是元组的链表,其排序用一行代码就可以完成:
sorted(Unite_List, key=lambda item:float(item[1]), reverse=True)
其中,Unite_List中的元素为(word, count)形式的元组,key后面指定的是排序的依据元素,lambda是一个内嵌的小函数(到现在也不是特别明白)。但至少明白,是按item[1]进行排序,即按count进行排序,如果要按word排序,可指定为item[0]。最后的参数reverse如果为「真」,则为逆序,默认值为假,是正序。
虽然,排序的内部过程大概都是要走两层循环,但在代码上Python则更容易一些。
简单的文件和数据操作
把运算的数据保存在文件和数据库,或者从文件或数据库中读取数据,也是常见的操作。C#中读取文本文件,需要声明一个FileStream用来指定文件路径和打开方式,即「读」或「写」或「追加」等。然后,使用StreamReader读取文件。读取的过程一般通过while循环来完成。文件读写之后,还建议对这两个对象执行Close操作。
但Python中,只需要指定一个文件读取变量就行:
FileRead = open('read.txt', 'r', encoding='utf-8')
content = FileRead.readlines()
for line in content:
print(line)
FileRead.close()
如果使用with结构,还可以把close省略掉。
对于数据库,也可以省掉open和close的过程,也不用像C#那样去声明一个Connection和Command对象。对于sqlite这种轻型的数据库,只需要提供数据库文件的路径,就可以直接执行sql语句:
conn = sqlite3.connect("sqlite.db")
conn.execute('create table ...')
conn.execute('insert into ...')
conn.execute('delete from ...')
conn.execute('update ...')
# 对于查询结果,可以通过遍历的形式读取
result = conn.execute('select id, name from people')
for row in result: #遍历查询结果的第一条记录
print(row[0], row[1]) #row[0]对应id,row[1]对应name
当然,Python主要用于实现数据处理,所以Python一般多用在后台,前端的UI处理还需要借助其他工具。