【实战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[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。  V1 }& {& H! J6 Z4 E

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: [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 0×3144140>

我们可以用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,每个元素表示一行。

文章来源:http://www.7po.com/thread-69704-1-1.html

 

 

Comment are closed.