(一)环境搭建
为了更好的学习Python,建议搭建一些软件环境来提高学习开发效率。
Python是一门开源的程序设计语言,是一种可交互执行的解释性脚本语言,非常适合简单应用和插件开发。如果只是编写xbmc插件,并且在xbmc里面进行调试的话,可以不用下载安装python软件包。在官方下载地址上有多个版本下载,因为XBMC内置的解释器是基于python2的,所以请大家下载2.7.3版本进行安装。特别注意,python 3在很多地方与python 2是不兼容的。
DreamPie是一个很好的Python Shell,我经常拿它来进行交互开发,或者作为高级计算器。Python有个优势,不像其他编译性语言一样,一定要等到程序写完,编译通过以后才能运行得到结果。而Python却可以在Python Shell中单独允许一条语句。比如说,你不知道字符串去空格的函数是不是strip了,那么很简单,直接到pytho shell中跑一句 ' abc '.strip() 看得到的结果是不是'a'就知道了,不对再去查文档也不迟。很多时候,一个很大的py文件里面某地方出错了,你完全可以把其中某一些语句挑出来单独在python shell里面去跑,省去反复不停的执行整个文件,而且减少依赖。
我是用的最多的Python开发环境是Ulipad,因为本身是python写的,跨平台,windows/linux/mac os都可以用。另外一款PyScripter是针对windows平台开发的优秀IDE。两者都具有语法高亮、自动缩进、类型浏览等多种特性,可以提高代码编制效率。当然不嫌麻烦的话,也可以使用记事本来写代码。
(二)变量
Python的变量是没有类型的,可以赋任意类型的值。变量不需单独定义,一旦赋值即可使用。print函数可以输出变量内容。- >>> url = 'http://www.baidu.com'
- >>> page = 4
- >>> print url
- http://www.baidu.com
- >>> print page
- 4
- >>> page += 5
- >>> url += '?page=' + str(page)
- >>> print url
- http://www.baidu.com?page=9
复制代码
上面的示例都是在python shell中交互运行的结果,以>>>开头的是输入的语句,其他的部分是显示结果。可以看到不需要像有些语言用var声明变量,也不需要int/string/char []*之类的类型定义符来进行定义。很简单,你想用的时候,直接赋值就行了,然后就可以对变量进行任意操作,比如用+=进行自加/连接,作为print函数的参数来输出变量的值。- >>> a = 123
- >>> print a
- 123
- >>> a = 1.24
- >>> print a
- 1.24
- >>> a = "I'm a fine"
- >>> print a
- I'm a fine
- >>> a = (1, 2.4, "hello", {'a': 0, 'b': 1})
- >>> print a
- (1, 2.4, 'hello', {'a': 0, 'b': 1})
复制代码
在上面的示例中,可以看到同一个变量可以赋不同的值。最后一个看起来稍微复杂点,将在后面的数据类型中一一讲到。
(三)数字
Python中的数字分整数和浮点数。python的整数有int和long,但是我们使用的时候不用管他。python中整数长度是没有限制的,这和别的很多语言不同,也就是说可以轻松的在python中完成大整数的运算。- >>> 2**30
- 186: 1073741824
- >>> 9**99
- 187: 29512665430652752148753480226197736314359272517043832886063884637676943433478020332709411004889L
- >>> 2358321783728157823*23594389258432 + 29512665430652752148753480226197736314359272517043832886063884637676943433478020332709411004889
- 210: 29512665430652752148753480226197736314359272517043832886063884693320105595399861474399840518425L<blockquote>>>> (1+2)*(39-13)
复制代码
在Python中,long类型的数值会在最后加上一个大写的L,但是你在输入的时候完全可以不用写。这是内部的类型转换,是无需关注和进行显示转换的。整数和浮点数进行运算时,会自动将整数转化为浮点后进行运算,得到浮点数结果。用int函数将浮点数转换为整数时,不进行四舍五入,而是简单的抛弃小数部分,这点需要注意。我们可以用int(x+0.5)的方式来进行四舍五入,当然也可以直接使用round()函数。
还有一点需要注意的是,/在python 2.x中,对于整数而言跟//的用法是相同的,都是取整数部分,这点很容易被忽略。%符号是用于取余数的运算符。divmod可以同时获得商和余数。- >>> 5/3
- 221: 1
- >>> 5%3
- 222: 2
- >>> 5/3.0
- 223: 1.6666666666666667
- >>> 5//3
- 224: 1
- >>> 5//3.0
- 225: 1.0
- >>> divmod(5, 3)
- 226: (1, 2)
复制代码
对于变量加1,没有像c语言里面那样的x++,一般用x=x+1,或者简化为x+=1。
(四)字符串
字符串是我们在程序中使用最多的类型。Python中没有字符类型,只有字符串。字符串可以用单引号或者双引号包围起来。可以用\符号在行的末尾进行换行,这是一种语法形式的换行,在很多地方使用,比如这行代码太长了。\换行的字符串实际并不包括换行符。- 236: 'bbb'
- >>> print 'hello'
- hello
- >>> print "hello"
- hello
- >>> 'hello' == "hello"
- 237: True
- >>> print 'hello \
- ... world'
- hello world
复制代码
单引号和双引号可以嵌套使用。这点在使用中很方便,比如一个html代码片段,里面有双引号,在字符串里面就必须进行转义。但是使用单引号就可以省却这个麻烦。- >>> "<a href=\"#\">test</a>"
- 238: '<a href="#">test</a>'
- >>> '<a href="#">test</a>'
- 239: '<a href="#">test</a>'
复制代码
把几个字符串放到一起,Python会自动进行拼接,也可以用+号进行显示拼接。- >>> print 'hello' "world"
- helloworld
- >>> print 'hello' +"world"
- helloworld
复制代码
字符串中包含换行符的,需要用\n进行表示。但是Python有一种很方便的方法,就是使用连续三个’或者"将字符串包围起来,则其中所有字符都原封不动的保留,包括空格和回车。这在构造一段html代码的时候很有用。- >>> print 'Dear J:\n Hi.\n yours.'
复制代码
正则表达式是我们在编写插件过程中最常见的技巧,但是正则表达式本身有\符号进行转义。比如\\表示\,\*表示*。但是\本身在python字符串中也是起转移作用的,那么要么你多转义几次,要么使用raw string,就是在字符串加上一个r,表示字符串内不需要进行转义。下面的示例在正则表达式中表示三个字符:^\*- >>> print '\\^\\\\\\*'
- \^\\\*
- >>> print r'\^\\\*'
- \^\\\*
复制代码
字符串是只读的,不能修改其中的某些字符。如果需要修改,必须重新构造一个字符串。- >>> s='abb'
- >>> s[0]='b'
- Traceback (most recent call last):
- File "<pyshell#374>", line 1, in <module>
- s[0]='b'
- TypeError: 'str' object does not support item assignment
- >>> s='b' + s[1:]
- >>> s
- 236: 'bbb'
复制代码
上例中的s[1:]用法在python中叫做切片(slice)。不仅对于字符串,对于后面讲到的tuple和列表都是同样的用法。基本的用法是s[start:end:step],start是切片开始的位置,python中从0开始,end表示结束的位置,注意s[end]这个字符本身不包含在内。这样end-start就是最后切片的长度,当然如果end小于start,得到的是空字符串''。step表示切片的步长,默认为1。简单来说,就是从start开始取,依次是start+step、start+step*2、...一致到小于end的所有字符。start、end、step都可以为负数,start和end负数表示从字符串后面开始数起,-1表示最后一个字符,step为负数就从后往前切片,这要求start大于end。len()函数用来获取字符串长度。几个参数都可以省略,start省略表示从0开始,end省略表示取到最后,step默认就是1了。说起来有点犯迷糊,看下面的例子就容易理解了。- >>> a='hello world'
- >>> len(a)
- 240: 11
- >>> a[:] #copy of string
- 241: 'hello world'
- >>> a[2:] #from the third
- 242: 'llo world'
- >>> a[2:-1] #except the last one
- 243: 'llo worl'
- >>> a[::2] # the even chars
- 244: 'hlowrd'
- >>> a[::-1] #reverse of string
- 245: 'dlrow olleh'
- >>> 'magnet:?xt=urn:btih:8fcffdf6062379a6a1a0505bb809919870d240eb&dn=%5B%E8%A5%BF%E6%B8%B8%E9%99%8D%E9%AD%94%E7%AF%87%5D.2013.HDTV.720p.x264.AAC-iSCG%5B%E5%9B%BD%E8%AF%AD%E4%B8%AD%E8%8B%B1%E5%AD%97%E5%B9%951.7G%5D'[20:60]
- 246: '8fcffdf6062379a6a1a0505bb809919870d240eb'
复制代码
下面的例子里面有一些字符串常见操作:- >>> 'hello world'.upper() #大写
- 247: 'HELLO WORLD'
- >>> 'HELLO WORLD'.lower() #小写
- 248: 'hello world'
- >>> 'hello world'.capitalize() #首字母大写
- 249: 'Hello world'
- >>> ' ab '.strip() #去空格
- 250: 'ab'
- >>> ' ab '.lstrip() #去除左侧空格
- 251: 'ab '
- >>> ' ab '.rstrip() #取出右侧空格
- 252: ' ab'
- >>> 'bc' in 'abcd' #判断是否包含某字符串
- 253: True
- >>> '中文test123'.encode('base64') #base64编码
- 262: '5Lit5paHdGVzdDEyMw==\n'
- >>> print '5Lit5paHdGVzdDEyMw==\n'.decode('base64') #base64解码
- 中文test123
- >>> '中文test123'.encode('hex').upper() #十六进制编码
- 264: 'E4B8ADE6968774657374313233'
- >>> print 'E4B8ADE6968774657374313233'.decode('hex')
- 中文test123
- >>> 'abcdabc'.replace('ab', '**') #替换
- 265: '**cd**c'
- >>> 'ab|cd|ef'.split('|') #按指定符号分割字符串
- 267: ['ab', 'cd', 'ef']
- >>> 'ab cd ef'.split() #按空格分割字符串
- 268: ['ab', 'cd', 'ef']
- >>> 'http://www.baidu.com'.partition('://') #按制定字符串分割成两部分,比split效率更高
- 271: ('http', '://', 'www.baidu.com')
- >>> ' , '.join(['hello', 'world', '!']) #连接字符串
- 270: 'hello , world , !'
复制代码
上面提到用join来将一个列表拼接成字符串的方法经常要用到,而且是效率最高的方法。一些需要动态拼接的字符串,都先append到一个列表,最后用join来形成最终的字符串。
检查字符串是否以xx开头或者结尾,分别用'abc'.startswith('ab')和'abc'.endswith('bc')的函数来校验。更复杂的需要用到正则表达式,在Python中有re模块对正则表达式进行支持。由于正则是一个非常庞大的话题,在此不做详解。
转换和格式化- >>> str(10)
- 272: '10'
- >>> str(1.5)
- 273: '1.5'
- >>> int('335')
- 274: 335
- >>> 'htt://%s/test/?page=%d' % ('www.baidu.com', 11)
- 275: 'htt://www.baidu.com/test/?page=11'
复制代码
(五)列表和tuple
列表(list)在Python中的地位也非常重要,在插件开发过程中更是经常用到。list有点像C语言的数组,可以按索引遍历访问其中的每一个元素,可以对其进行修改。但是list与c的数组有天壤之别,便利之处也是数组遥不可及的。
首先,list长度不固定,可以任意追加、插入、删除元素,也可以一个元素都没有,即经常用到的空列表[]。从某种意义上说,list更像数据结构里面的链表,在内存中并不占有连续的空间。list元素也不限定数据类型,可以是任意Python类型,数字、字符串、字典...,甚至是另一个list,或者一个函数。
list可以用索引进行访问,比如x[2];可以切片,比如x[:-3];还可以迭代for item in aList: print item。下面来看看list长什么样子吧。- >>> urls = []
- >>> urls.append('www.baidu.com')
- >>> urls.append('www.google.com')
- >>> urls.insert(0, 'xbmc.org') #注意顺序,在最前方插入
- >>> urls.extend(['a', 'b', 'c'])
- >>> urls
- 278: ['xbmc.org', 'www.baidu.com', 'www.google.com', 'a', 'b', 'c']
- >>> urls.pop() #pop the last one and return
- 279: 'c'
- >>> urls
- 280: ['xbmc.org', 'www.baidu.com', 'www.google.com', 'a', 'b']
- >>> urls.pop(0) # pop the first
- 281: 'xbmc.org'
- >>> urls
- 282: ['www.baidu.com', 'www.google.com', 'a', 'b']
- >>> urls[2:]
- 283: ['a', 'b']
- >>> urls[2] = [1,2,3]
- >>> urls
- 284: ['www.baidu.com', 'www.google.com', [1, 2, 3], 'b']
- >>> urls[2:2] = [4, 5, 6]
- >>> urls
- 285: ['www.baidu.com', 'www.google.com', 4, 5, 6, [1, 2, 3], 'b']
- >>> len(urls)
- 286: 7
复制代码
从上面的示例可以看到,可以在列表中任意追加、插入、替换元素。请大家不要误会,list不是一定要从空列表[]开始。你完全可以一开始就 urls = ['a', 'b','c']。切片的操作和字符串类似,只不过字符串不能修改,而列表是可以修改的。urls[2:2]=[4,5,6]就利用这个技巧,在2的位置上加了三个元素,注意和urls[2]=进行区别。extend函数直接将另一个list直接追加到最后,省的一个一个append。
列表可以查找和删除指定元素,不仅仅是通过索引位置,还可以根据元素的值进行定位和删除,分别是index和remove函数。需要注意的是,如果多个元素值相同的话,只针对第一个出现的元素。sort和reverse函数分别对list进行排序和反转,这两个函数都不返回值,这点需要注意一下。如果需要排序结果,但不影响原list的话,就使用sorted函数。- >>> urls.append(4)
- >>> urls.count(4)
- 287: 2
- >>> urls.index(4)
- 288: 2
- >>> urls.remove(4)
- >>> urls
- 289: ['www.baidu.com', 'www.google.com', 5, 6, [1, 2, 3], 'b', 4]
- >>> urls.sort()
- >>> urls
- 290: [4, 5, 6, [1, 2, 3], 'b', 'www.baidu.com', 'www.google.com']
- >>> urls.reverse()
- >>> urls
- 291: ['www.google.com', 'www.baidu.com', 'b', [1, 2, 3], 6, 5, 4]
- >>> sorted(urls)
- 292: [4, 5, 6, [1, 2, 3], 'b', 'www.baidu.com', 'www.google.com']
复制代码
range函数返回一个数字列表。参数和切片有些类似,可以指定起至值和step。看下面的例子就明白了:- >>> range(10)
- 293: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- >>> range(5, 10)
- 294: [5, 6, 7, 8, 9]
- >>> range(10, -1, -2)
- 295: [10, 8, 6, 4, 2, 0]
复制代码
因为返回的结果是一个list,是需要在内存中真实存在的。所以如果你需要一个从1到一百万的序列,请不要使用range函数,而是用xrange,得到的是一个迭代器(iterator),不会一次性在内存中生成。
下面要讲一下关于迭代的问题。对于任意可以迭代的数据,我们用 for 变量 in 数据 的语法形式来进行访问。我们已经知道,list可以根据索引访问。那么类似c语言数组的做法,很容易想到的是下面的用法:- >>> aList = ['a', 'b', 3, 4, 'e', 'f', 3.9]
- >>> for i in range(len(aList)):
- ... print aList
- a
- b
- 3
- 4
- e
- f
- 3.9
复制代码
但是,这种访问方式很明显多此一举了。按照Python的思想,要用最简单的语句最多的事情。- >>> for item in aList:
- ... print item
- a
- b
- 3
- 4
- e
- f
- 3.9
复制代码
即简单,又简洁。如果同时确实元素的索引值,可以用enumerate函数- >>> for i, item in enumerate(aList):
- ... print i, item
- 0 a
- 1 b
- 2 3
- 3 4
- 4 e
- 5 f
- 6 3.9
复制代码
enumerate返回的一个元素为tuple的list,可能类似[(0, 'a'), (1, 'b'), ...]这样的形式。我们在for里面用到了两个变量,这叫做unpack(好像是这么称呼),就是将一个序列解开到多个变量。顺便先提一下, a,b这样的形式就叫做tuple,它和(a,b)是一样的,类似list,区别在于它不能修改。我们来看看upack怎么用。- >>> a,b = [1,2]
- >>> a, b
- 296: (1, 2)
- >>> print a, b
- 1 2
- >>> a, b = ('hello', 'world')
- >>> print a,b
- hello world
- >>> (a, b, c) = [3, 4, 5]
- >>> print a, b, c
- 3 4 5
- >>> name, url = ('百度', 'www.baidu.com')
- >>> print name
- 百度
- >>> print url
- www.baidu.com
- >>> name, url = url, name
- >>> print name
- www.baidu.com
- >>> print url
- 百度
复制代码
可以看到,unpack在变量赋值的过程中是非常有用的。name, url = aList 相当于name=aList[0] url=aList[1]。显然前面的方式更加简洁明了。甚至我们用name, url = url, name这样的语句,简单的交换了两个变量的值,这在c语言里面不用第三个变量中转是无法做到的。
list的迭代使用的确很方便,很强大。但是很多情况下还不需要这么复杂,因为有list comprehension,就是用一种表达式将原来的list进行运算变形,得到新的表达式。比如我需要得到1-10这10个数的平方,保存为一个列表。采用传统的方法:- >>> aList = []
- ... for i in range(11):
- ... aList.append(i*i)
- >>> aList
- 298: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
复制代码
你再看看下面更简洁的方法:- 298: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
- >>> aList = [i*i for i in range(11)]
- >>> aList
- 299: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
复制代码
别看这个例子很简单,其实在我们写程序的过程中经常会用到,大大简化我们的程序。有兴趣也可以翻翻我写的插件源代码,到处充斥这这样的应用。
我们还可以用if来对产生的结果进行过滤。比如上例中,我要挑出3次方被3除余2的数字的平方(有点绕口)。- <blockquote>>>> [i*i for i in range(11) if i**3 % 3 == 2]
复制代码
再来说说tuple,前面已经大致提到过。形如(1,2,3)用括号和逗号构造的序列就叫做tuple,有的翻译为元组,我觉得不习惯。它和list很相似,可以用索引进行访问,可以进行迭代,可以切片。tuple和list最大的区别就是它和字符串一样,不能对它进行任何修改。字符串从某种意义来讲,可以认为是单个字符组成的tuple。
tuple用于某些不希望别人修改它的场合,比如作为函数参数传入,作为字典的key等等。构造tuple很简单,需要注意的是,如果一个tuple只有一个元素,不是(1)这样的形式,这样会当作括号符进行运算,得到1这个整数。正确的语法是(1,),就是后面一定要有一个逗号,虽然有点怪异,但是习惯就好了。讲到这里,顺便提一下,tuple、list和我们后面要讲到的dict(字典),最后一个元素后面都可以带一个逗号,不会出现语法错误。我们经常会这么干,便于追加记录,比如
复制代码
tuple也可以用+连接,构造新的tuple。下面的例子介绍一些常见的tuple形式和运算- >>> (1, 2, 'a', 'b')
- 300: (1, 2, 'a', 'b')
- >>> (1, 2, 'a', 'b') + (4, 5)
- 301: (1, 2, 'a', 'b', 4, 5)
- >>> (1, 2, 'a', 'b') + (6, )
- 302: (1, 2, 'a', 'b', 6)
- >>> ()
- 303: ()
- >>> (1,)
- 304: (1,)
复制代码
tuple和list可用tuple和list内置函数进行相互转换- >>> aList = range(10)
- >>> aList
- 307: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- >>> t = tuple(aList)
- >>> t
- 308: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
- >>> list(aList)
- 309: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
复制代码
迭代同样适用于tuple- >>> ''.join(str(i) for i in t)
- 311: '0123456789'
复制代码
上例中,t是一个10个数字的tuple。通过list comprehension表达式,将t里面的每一个数字用str函数转换成字符串。最后的得到一个generator用''.join连接在一起,形成最终的字符串。中间的表达式的结果实际上是一个generator,不用了解太深,知道可以这么用就可以了。- >>> (str(i) for i in t)
- 312: <generator object <genexpr> at 0x3144140>
复制代码
我们可以用in来判断某个指定的元素在list/tuple中是否存在。比如 'a' in ('a', 'b'),'b' not in ['a', 'b']
最后,来看一个稍微复杂点的例子吧,将文件中以LOG: 开头的行显示出来,并且去掉LOG:。- print ''.join([line[4:] for line in open('a.txt') if line.startswith('LOG:')])
复制代码
其中open函数打开一个文件,返回一个每行数据的迭代,基本上你可以认为返回一个list,每个元素表示一行。
|