【实战XBMC插件开发】之磨刀篇---Python基础和实用技巧
(一)环境搭建为了更好的学习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='b'
[*]Traceback (most recent call last):
[*]File "<pyshell#374>", line 1, in <module>
[*] s='b'
[*]TypeError: 'str' object does not support item assignment
[*]>>> s='b' + s
[*]>>> s
[*]236: 'bbb'
复制代码
上例中的s用法在python中叫做切片(slice)。不仅对于字符串,对于后面讲到的tuple和列表都是同样的用法。基本的用法是s,start是切片开始的位置,python中从0开始,end表示结束的位置,注意s这个字符本身不包含在内。这样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 #from the third
[*]242: 'llo world'
[*]>>> a #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'
[*]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;可以切片,比如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
[*]283: ['a', 'b']
[*]>>> urls =
[*]>>> urls
[*]284: ['www.baidu.com', 'www.google.com', , 'b']
[*]>>> urls =
[*]>>> urls
[*]285: ['www.baidu.com', 'www.google.com', 4, 5, 6, , 'b']
[*]>>> len(urls)
[*]286: 7
复制代码
从上面的示例可以看到,可以在列表中任意追加、插入、替换元素。请大家不要误会,list不是一定要从空列表[]开始。你完全可以一开始就 urls = ['a', 'b','c']。切片的操作和字符串类似,只不过字符串不能修改,而列表是可以修改的。urls=就利用这个技巧,在2的位置上加了三个元素,注意和urls=进行区别。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, , 'b', 4]
[*]>>> urls.sort()
[*]>>> urls
[*]290: , 'b', 'www.baidu.com', 'www.google.com']
[*]>>> urls.reverse()
[*]>>> urls
[*]291: ['www.google.com', 'www.baidu.com', 'b', , 6, 5, 4]
[*]>>> sorted(urls)
[*]292: , 'b', 'www.baidu.com', 'www.google.com']
复制代码
range函数返回一个数字列表。参数和切片有些类似,可以指定起至值和step。看下面的例子就明白了:
[*]>>> range(10)
[*]293:
[*]>>> range(5, 10)
[*]294:
[*]>>> range(10, -1, -2)
[*]295:
复制代码
因为返回的结果是一个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 =
[*]>>> a, b
[*]296: (1, 2)
[*]>>> print a, b
[*]1 2
[*]>>> a, b = ('hello', 'world')
[*]>>> print a,b
[*]hello world
[*]>>> (a, b, c) =
[*]>>> 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 url=aList。显然前面的方式更加简洁明了。甚至我们用name, url = url, name这样的语句,简单的交换了两个变量的值,这在c语言里面不用第三个变量中转是无法做到的。
list的迭代使用的确很方便,很强大。但是很多情况下还不需要这么复杂,因为有list comprehension,就是用一种表达式将原来的list进行运算变形,得到新的表达式。比如我需要得到1-10这10个数的平方,保存为一个列表。采用传统的方法:
[*]>>> aList = []
[*]... for i in range(11):
[*]... aList.append(i*i)
[*]>>> aList
[*]298:
复制代码
你再看看下面更简洁的方法:
[*]298:
[*]>>> aList =
[*]>>> aList
[*]299:
复制代码
别看这个例子很简单,其实在我们写程序的过程中经常会用到,大大简化我们的程序。有兴趣也可以翻翻我写的插件源代码,到处充斥这这样的应用。
我们还可以用if来对产生的结果进行过滤。比如上例中,我要挑出3次方被3除余2的数字的平方(有点绕口)。
[*]<blockquote>>>>
复制代码
再来说说tuple,前面已经大致提到过。形如(1,2,3)用括号和逗号构造的序列就叫做tuple,有的翻译为元组,我觉得不习惯。它和list很相似,可以用索引进行访问,可以进行迭代,可以切片。tuple和list最大的区别就是它和字符串一样,不能对它进行任何修改。字符串从某种意义来讲,可以认为是单个字符组成的tuple。
tuple用于某些不希望别人修改它的场合,比如作为函数参数传入,作为字典的key等等。构造tuple很简单,需要注意的是,如果一个tuple只有一个元素,不是(1)这样的形式,这样会当作括号符进行运算,得到1这个整数。正确的语法是(1,),就是后面一定要有一个逗号,虽然有点怪异,但是习惯就好了。讲到这里,顺便提一下,tuple、list和我们后面要讲到的dict(字典),最后一个元素后面都可以带一个逗号,不会出现语法错误。我们经常会这么干,便于追加记录,比如
[*]a = [
[*] 'a',
[*] 'b',
[*]]
复制代码
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:
[*]>>> t = tuple(aList)
[*]>>> t
[*]308: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
[*]>>> list(aList)
[*]309:
复制代码
迭代同样适用于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( for line in open('a.txt') if line.startswith('LOG:')])
复制代码
其中open函数打开一个文件,返回一个每行数据的迭代,基本上你可以认为返回一个list,每个元素表示一行。
给力!! 介是神马?!! kkkkkkkkkkkkkkkkkk 我来顶一下.. 看看学习 看看怎么样? 看看学习 精华内容,楼主V5!
页:
[1]
