首页 > 代码库 > Python 点滴 I

Python 点滴 I

为什么使用Python

1. 软件质量

2. 开发效率

3. 可移植性

4. 标准库支持

5. 好玩

Python全景

#模块,语句,表达式,对象)

1. 程序由模块组成

2. 模块包含语句

3. 语句包含表达式

4. 表达式建立并处理对象

动态类型

Python即是动态类型又是强类型,在C/C++/Java强类型语言中,要先声明,后使用

动态类型:自动跟踪用户定义的类型而不需要预先定义 

s=1的话, s*2就等于2

s=‘hello‘的话, s*2就等于‘hellohello‘

random模块

1. 可做随机数生成器

>>> import random
>>> random.random()
0.26637487298372353

2. 可做随机选择

>>> random.choice([1,2,3,4,5,6]);random.choice(range(12))
2
7

序列

#字符串,列表及元祖

>>> S = ‘A\nB\tC‘
>>> len(S)
5

>>>s = ‘Spam‘

>>>s[::-1]    #反向切片

‘mapS‘

>>>‘B‘+s[1:]  #字符拼接

‘Bpam‘

>>> y = s[:]  #用于字符串的深度拷贝 

‘Spam‘

#Python中的多态: 操作的意义取决于操作的对象,给Python带来更大的简洁性和灵活性.

>>>s + ‘xyz‘    

‘Spamxyz‘ 

>>> s = 1;  s + 2;

3

#字符串不可变性,在Python核心类型中,

不可变: 数字,字符串,元祖

可变  : 列表,字典

>>> s = ‘Spam‘
>>> s[0] = ‘X‘  #字符串不可更改
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ‘str‘ object does not support item assignment

>>> s[0]+‘X‘    #但是我们创造新的对象,不改变原来的字符串
‘SX‘
>>> s
‘Spam‘

>>> s.replace(‘pam‘,‘B‘) #运用replace方法,其实是创建了新的字符串对象
‘SB‘
>>> s                    #不会改变原字符串的值
‘Spam‘

寻求帮助

首选:dir和help

其次:Python标准库参考文件(本地) 和 https://www.python.org/doc/(官方网站)

>>> dir(s)  #__开头:变量名,用来表示Python的实现细节的命名规则,其他则为方法
[‘__add__‘, ‘__class__‘,‘__doc__‘,‘index‘,‘ljust‘, ‘lower‘, ‘lstrip‘, ‘partition‘, ‘replace‘,
‘rfind‘, ‘rindex‘, ‘rjust‘, ‘rpartition‘, ‘rsplit‘,‘zfill‘]

>>> help(s.zfill) #dir给出了方法列表,具体如何使用求助于help
Help on built-in function zfill:

zfill(...)
    S.zfill(width) -> string


    Pad a numeric string S with zeros on the left, to fill a field
    of the specified width.  The string S is never truncated.

列表

可变,比数组强大,无规定类型的约束

>>> l = [123,1.23]
>>> l.append(‘Hello‘)

>>> l
[123, 1.23, ‘Hello‘]
>>> l.pop(1)
1.23
>>> l
[123, ‘Hello‘]

嵌套

核心数据支持任意的嵌套,列表包含字典,并在字典中包含另外一个列表,直接应用时实现矩阵,或者多维数组。

>>> M = [[1,2,3],\
         [4,5,6],\
         [7,8,9]]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

>>> M[1]      #取第二行
[4, 5, 6]
>>> M[1][2]   #最后一个元素
6

列表解析

更高级的列表操作(list comprehension expression)列表解析表达式,提供了可以处理矩阵这样的强大工具,实际上很有用,且有速度上的优势(一般快两倍),返回是列表.

>>> cols = [row[1] for row in M]             #取每行元素的第二列
>>> cols
[2, 5, 8]

>>> [row[1]+1 for row in M]                  #在原先的基础上+1
[3, 6, 9]
>>> [row[1] for row in M if row[1]%2 == 0]   #用if语句只取偶数那部分
[2, 8]

>>> diag = [M[i][i] for i in [0,1,2]]        #取M[0][0],M[1][1],M[2][2]
>>> diag
[1, 5, 9]

>>> double = [s *2 for s in ‘SB‘]
>>> double
[‘SS‘, ‘BB‘]

字典

可变,非序列,Python中唯一的映射型。映射是一种其他对象的集合,它们是通过键而不是相对位置来存储.键无序,只是简单将键映射到值. {键:值},因为字典是无序的,所以,取出来的未必是我们想要的。

>>> d = {‘a‘:1,‘b‘:2,‘c‘:3}
>>> d
{‘a‘: 1, ‘c‘: 3, ‘b‘: 2}

如果真要排序的话,用sort.

>>> ks = d.keys()
>>> ks
[‘a‘, ‘c‘, ‘b‘]
>>> for key in ks:
print key, ‘==>‘, d[key]


a ==> 1
c ==> 3
b ==> 2
>>> ks.sort()
>>> ks
[‘a‘, ‘b‘, ‘c‘]
>>> for key in ks:
print key,‘=>‘, d[key]

a => 1
b => 2
c => 3

或者

>>> d
{‘a‘: 1, ‘c‘: 3, ‘b‘: 2}
>>> for key in sorted(d):
print key,‘=>‘,d[key]

a => 1
b => 2
c => 3

小技巧:键值判断if

>>> D
{‘a‘: 1, ‘c‘: 3, ‘b‘: 2, ‘d‘: 4}
>>> D.has_key(‘e‘)
False

>>> if not D.has_key(‘e‘):
print ‘e key missing...‘
e key missing...

这里可以使用(get方法,成员表达式,try语句捕捉异常)来避免键值不存在.

file

Python核心类型, 字符串,列表,字典,元祖,文件

注意f.read()和f.readlines()区别,前者读取是字符串,后者返回为列表.

>>> f = file(‘data.txt‘,‘w‘)
>>> f.write(‘Hello\n‘)
>>> f.write(‘World\n‘)
>>> f.close()

>>> f = file(‘data.txt‘)
>>> f1 = f.read()
>>> f1
‘Hello\nWorld\n‘
>>> f1.split()
[‘Hello‘, ‘World‘]

>>> f = open(‘data.txt‘)
>>> f.readlines()
[‘Hello\n‘, ‘World\n‘]

open函数能实现绝大多数文件如理,Python提供额外的文件类工具来处理更高级的任务:pipes, fifos, sockets, keyed-access files, 对象持久,基于描述符的文件,关系数据库和面向对象数据库接口。

破坏代码的灵活性

#至少可以用下面的三种方法来校验代码的灵活性

>>> if type(L) == type([]):
print ‘Yes‘
Yes

>>> if type(L) == list:
print ‘Yes‘
Yes

>>> if isinstance(L,list):
print ‘Yes‘
Yes

#在代码中检验了特定的类型,实际上破坏了它的灵活性,即限制它只能使用一种类型工作。没有这样的测试,代码也许能够使用整个范围的类型工作。这个Python多态的思想.是其关键的思想.尽管Python是面向对象语言,但类是Python的一个可选特性,Python即可以使面向过程语言,也可以使面向对象的语言。很灵活.

str和repr

从技术上来说,默认的交互模式和打印模式的区别相当于repr和str函数的区别

>>> num
0.3333333333333333
>>> repr(num)
‘0.3333333333333333‘
>>> str(num)
‘0.333333333333‘

这两个函数都会把任意对象变换成它们的字符串表达。

repr:默认的交互式回显,产生的结果看起来就像它们是代码

str:  打印语句,变换得到一种对用户更加友好的格式.

/ 除法运算

>>> 5/2
2

>>> from __future__ import division  #导入未来可能采用的模式的结果
>>> 5/2
2.5

八进制和十六进制

八进制: 0开头,并紧跟八进制数字0-7的字符串

十六进制:以0x,0X开头,后面0-9数字或(a-Af-F)构成的字符串

>>> 01,010,0100
(1, 8, 64)
>>> 0x01,0X10,0xFF
(1, 16, 255)

可以用相应的函数在进制之间转化:

>>> oct(64),hex(255)    #将十进制分别转为八进制,十六进制
(‘0100‘, ‘0xff‘)

>>> int(‘0100‘),int(‘0100‘,8),int(‘0100‘,16) #int函数分别加要转换的进制,默认是10进制
(100, 64, 256)

也可以用eval函数

>>> eval(‘100‘),eval(‘0100‘),eval(‘0x100‘)

(100, 64, 256)

如果想通过字符串表达式来表示,则可以用如下方式:

>>> ‘%d %o %x %X‘ % (100,64,255,255)
‘100 100 ff FF‘

小数对象

>>> 0.1 + 0.1 + 0.1 - 0.3         #直接回显
5.551115123125783e-17

>>> print 0.1 + 0.1 + 0.1 - 0.3   #用打印,显示友好,但改善不大
5.55111512313e-17

>>> from decimal import Decimal   #必须导入decimal模块
>>> Decimal(‘0.1‘)+Decimal(‘0.1‘)+Decimal(‘0.1‘)-Decimal(‘0.3‘)
Decimal(‘0.0‘)

>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal(‘0.1428571428571428571428571429‘)

>>> decimal.getcontext().prec = 4
>>> Decimal(1)/Decimal(7)
Decimal(‘0.1429‘)

Pyton的动态类型

在Python中,类型是运行过程中自动决定的,而不是代码声明.

对象的垃圾收集

>>> a = 1            #先给变量a赋值整数1
>>> a = ‘New Year!‘  #再给字符串的引用赋给a

>>> a = [1,2,3,4]

则前一个对象占用的空间就会被回收(如果,它没有被其它对象或变量名引用的话).在Python中类型属于对象,变量名只是对象的引用.对象的引用值在此过程中逐个被丢弃。每一次a被赋值给了一个新对象,Python都回收了对象的空间. 当它赋值为[1,2,3,4]时,对象1,和‘New Year‘马上会被回收,假设它没有其它对象引用的话: 对象的空间自动放入自由内存空间池,等待后面的对象使用. 

在内部Python是通过保持用每个对象中的计数器记录引用指到这个对象上的次数来完成这一功能,一旦这个计数器被设置为0,这个对象的内存空间就会自动回收。 像前面一样,a每次被赋值给一个新对象,而前一个对象的引用计数器变为0,导致它的空间被回收。垃圾收集最直接,可感受的好处就是:可以再脚本中任意使用对象而不需要考虑释放内存空间. 在程序运行时,Python将会清理那些不再使用的空间。 和C/C++这些底层语言相比,省去了大量的基础代码。 Python会使用引用值计算的垃圾收集策略,自动回收无用对象的内存空间。每个对象都会记录引用其的变量名,数据结构等次数,一旦计数值为0,Python就会释放该对象的空间。这种方式意味着Python不用停下来扫描所有内存,从而寻求释放的无用空间. 注:一个额外的垃圾组件也会收集循环对象

共享引用和原处修改

Python中可变的对象:列表,字典和class中定义的对象

列表支持原处修改,所以在列表中进行修改会改变其值.

>>> L1 = [2,3,4]
>>> L2 = L1
>>> L1[0]=1
>>> L1;L2
[1, 3, 4]
[1, 3, 4]

要想L2的值不做改动的话,必须对L1做一份拷贝.

>>> L1 = [1,2,3]
>>> L2 = L1[:]  #一个有相同的值,但在不同内存片区的对象
>>> L1[0]=21
>>> L1;L2
[21, 2, 3]
[1, 2, 3] 

>>> import copy
>>> Y = 1
>>> X = copy.copy(Y)
>>> X = copy.deepcopy(Y)

【检查变量相等

Python中有两种方法来检查两个变量是否相等.如下: 

>>> L = [1,2,3]
>>> M = L
>>> L == M  #==操作符,测试两个被引用的对象的值是否相等,在Python用作相等检查
True
>>> L is M  #is操作符号,检查引用对象的同一性.如果两个变量名指向同一个对象,则为Ture
True

再看下面一种情况:

>>> M = [1,2,3]
>>> L = [1,2,3]  #M,L为两个不同的object
>>> M == L       #M,L的值是相等的
True
>>> M is L       #M,L为不同的Object,即不同的内存块
False
>>> id(M);id(L)
41080456L
41083848L

但是如果是数字类型的话,会有小许差别.

>>> X = 42
>>> Y = 42
>>> X == Y    #值显然相同
True
>>> X is Y #因为数字和字符串被缓存并复用了,所以两者是同一个对象.
True

如果深究的话,可以查询一个对象被引用的次数,用sys模块中的getrefcount函数

>>> import sys
>>> sys.getrefcount(42) #查看42这个数字被引用的次数,有13次重复引用
13

>>> str(u‘spam‘);unicode(‘spam‘) #普通字符串和unicode字符串相互转化

‘spam‘
u‘spam‘

切片操作的实际应用

1. [:]可以用这个来做深度拷贝

2. import sys
print sys.argv[1:]    #查看参数个数,文件名不包括在内

输出结果:

D:\python>python echo.py  -help -start -stop
[‘-help‘, ‘-start‘, ‘-stop‘]

3. 文本操作,去掉最末\n(换行符)line[:-1]

当然也可以用rstrip()去掉后面的换行符

字符串转换工具

>>> int("42");str(42)
42
‘42‘
>>> repr(42),`42`
(‘42‘, ‘42‘)

其他转换

>>> float("1.5")
1.5

>>> text = "1.234E-10"
>>> float(text)
1.234e-10

相应的可用内置函数eval来进行操作

字符串代码转换

>>> (115, ‘s‘)
(115, ‘s‘)

>>> S = ‘5‘
>>> S = chr(ord(S)+1)
>>> S
‘6‘

>>> ord(‘5‘) - ord(‘0‘)
5

#转换可以与循环语句配合使用,可以将一个表示二进制的字符串转换为等值的整数--每次都将当前的值*2,并加上下一位数字的整数值

>>> B = ‘1101‘
>>> I = 0
>>> while B:
...   I = I*2 + (ord(B[0])-ord(‘0‘))
...   B = B[1:]
...
>>> I
13

字符串格式化

>>> x 
1.2345678899999999
>>> "%-6.2f | %05.2f | %+06.1f" % (x,x,x)  #(-)左对齐,(+)正负号,(0)补齐,整数,小数点后位数
‘1.23   | 01.23 | +001.2‘

>>> "%s" % x,str(x)     #两者效果一样
(‘1.23456789‘, ‘1.23456789‘)

#基于字典的字符串格式化,允许右边字典中键来提取对应的值,在生成XML或HTML程序中往往会应用这一技术。你可以建一个数值字典,并利用基于键的引用的格式一次性替换他们.

>>> "%(name)s age is: %(age)s " % {‘name‘:‘Bob‘,‘age‘:40}
‘Bob age is: 40 ‘

再比如:

>>> reply = ‘‘‘
... Greeting...
... Hello %(name)s!
... Your age squared is %(age)s
... ‘‘‘
>>> values = {‘name‘:‘Bog‘,‘age‘:40}
>>> print reply % values

Greeting...
Hello Bog!
Your age squared is 40

这样的小技巧也常与内置函数vars联起来一同使用,这个函数返回的字典包含了所有在本函数调用时存在的变量

>>> food = ‘spam‘
>>> age  = 40
>>> vars()
{‘__builtins__‘: <module ‘__builtin__‘ (built-in)>, ‘__name__‘: ‘__main__‘, ‘food‘: ‘spam‘, ‘ages‘: 40, ‘__doc__‘: None}
>>> "%(age)d %(food)s" % vars()
‘40 spam‘

>>> "aa$bbb$cc$".replace(‘$‘,‘SB‘)  #replace,可以替换不定长的字符串
‘aaSBbbbSBccSB‘

#有点繁琐的替换

>>> S = ‘xxxxSPAMxxxxSPAMxxxx‘
>>> W = S.find(‘SPAM‘)
>>> W
4
>>> S = S[:W]+‘EGGS‘+S[W+4:]
>>> S
‘xxxxEGGSxxxxSPAMxxxx‘

#由于字符串是不可更改,replace每次生成一个新的对象

>>> S = ‘xxxxSPAMxxxxSPAMxxxx‘
>>> S.replace(‘SPAM‘,‘EGGS‘)
‘xxxxEGGSxxxxEGGSxxxx‘
>>> S = ‘xxxxSPAMxxxxSPAMxxxx‘
>>> S.replace(‘SPAM‘,‘EGGS‘,1) #替换一个
‘xxxxEGGSxxxxSPAMxxxx‘

#下面是另外一种替换的方式

>>> S = ‘spammy‘
>>> L = list(S)
>>> L
[‘s‘, ‘p‘, ‘a‘, ‘m‘,‘m‘,‘y‘]
>>> L[2] = ‘x‘

>>> L[3] = ‘x‘
>>> S = ‘‘.join(L)
>>> S
‘spaxxy‘
split

split,默认是TAB,空格来分割,也可以,或其他分割符,当然也可以是长字符串

>>> S = "This‘sSPAMaSPAMdog!"
>>> S.split(‘SPAM‘)
["This‘s", ‘a‘, ‘dog!‘]

列表

Python中最灵活的有序集合对象类型,可以包含任何类型,可原处修改. 在列表中,删除某个片段和赋空值是等价的

>>> L = [1,2,3,4]
>>> del L[1:3]
>>> L
[1, 4]

>>> L = [1,2,3,4]
>>> L[1:3] = []
>>> L
[1, 4]

【get

字典中,防止取不到值,可以用get,不至于报错:

>>> D2
{‘eggs‘: 3, ‘ham‘: 1, ‘spam‘: 2}
>>> D2.get(‘spam‘)
2

>>> D2.get(‘hamm‘) #不存在的话,为None
>>> D2.get(‘hamm‘,‘Key Error: The key not exist!‘) #可以自定义输出
‘Key Error: The key not exist!‘

字典中的update方法

类似于列表中的合并

>>> D2
{‘eggs‘: 3, ‘ham‘: 1, ‘spam‘: 2}
>>> D3 = {‘toast‘:4,‘muffn‘:5}
>>> D2.update(D3)
>>> D2
{‘toast‘: 4, ‘muffn‘: 5, ‘eggs‘: 3, ‘ham‘: 1, ‘spam‘: 2}

如有重复键的话,则会覆盖

>>> D2 = {‘eggs‘: 3, ‘ham‘: 1, ‘spam‘: 2}
>>> D3 = {‘eggs‘:4}
>>> D2.update(D3)
>>> D2
{‘eggs‘: 4, ‘ham‘: 1, ‘spam‘: 2}

字典中的一个应用

>>> table = {‘Python‘:‘Guido van Rossum‘,
...          ‘Perl‘  :‘Larry Wall‘,
...          ‘Tcl‘   :‘John Ousterhout‘}
>>> language = ‘Python‘
>>> creator  = table[language]
>>> creator
‘Guido van Rossum‘
>>> for lang in table.keys():
...   print lang,‘\t‘,table[lang]
...
Python  Guido van Rossum
Tcl     John Ousterhout
Perl    Larry Wall


字典中常用的遍历

>>> D1
{‘eggs‘: 3, ‘ham‘: 1, ‘spam‘: 2}
>>> for key,value in D1.items():    #依照键,值来遍历 D1.items()
...   print key,‘\t‘,D1[key]
...
eggs    3
ham     1
spam    2
>>> for key in D1.keys():           #遍历键
...   print key,
...
eggs ham spam
>>> for value in D1.values():       #遍历值
...   print value,
...
3 1 2

使用字典模仿灵活的列表

>>> L = []
>>> L[99] = ‘spam‘   #在列表中这样使用是错误的,不能越界。列表有序,有界
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

但在字典中却可以,因为字典是无序,无界

>>> D = {}
>>> D[99] = ‘spam‘
>>> D
{99: ‘spam‘}

字典用于稀疏数据结构

即稀疏矩阵

>>> M = {}
>>> M[(2,3,4)] = 88   #用于存储坐标为(2,3,4)的值
>>> M[(5,6,7)] = 99   #用于存储坐标为(5,6,7)的值
>>> M
{(2, 3, 4): 88, (5, 6, 7): 99}
>>> X = 2;Y = 3;Z = 4;
>>> M[(X,Y,Z)]        #根据坐标来查找其值
88
>>> M[(2,3,5)]        #该坐标不存在,所以报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: (2, 3, 5)


避免missing-key错误: 从编程的角度来看,get方法是其中最简单的。

可以用下面三种方法来避免missing-key的错误:

1. 用if来判断

>>> if M.has_key((2,3,6)):
...   print M[(2,3,6)]
... else:
...   print 0
...
0

2. 用try来扑捉异常

>>> try:
...   print M[(2,3,6)]
... except KeyError:
...   print 0
...
0

3. 用get方法

>>> M.get((2,3,6),0)  #不存在的话,显示后面的信息
0
>>> M.get((2,3,4),0)  #如存在的话,显示找到的坐标值
88

字典扮演的角色

1.字典可以取代搜索数据结果,因为用键进行索引是一种搜索操作,字典其实是一种哈希索引

2.还可以表示各种结构化信息.

#比如下面,随时通过新键赋值来填写字典的例子

>>> rec[‘age‘]  = 45
>>> rec[‘name‘] = ‘mel‘
>>> rec[‘age‘]  = 45
>>> rec[‘job‘]  = ‘trainer/writer‘
>>> print rec[‘name‘]
mel

#特别是嵌套的时候,Python可以很轻松的表达结构化信息

>>> mel = {‘name‘:‘Mark‘,
...        ‘jobs‘:[‘trainer‘,‘writer‘],
...        ‘webs‘:‘www.xxx.com‘,
...        ‘home‘:{‘state‘:‘CD‘,‘zip‘:80513}}

当读取嵌套函数时,只需要把索引操作串起来即可:

>>> mel[‘name‘];mel[‘jobs‘]
‘Mark‘
[‘trainer‘, ‘writer‘]

>>> mel[‘jobs‘][1]
‘writer‘
>>> mel[‘home‘][‘zip‘]
80513

创建字典的五种方法

方法一:

#如果事先能拼出整个字典,则此方法比较方便

>>> D1 = {‘name‘:‘Bob‘,‘age‘:40}

方法二:

#如果需要动态地建立字典的一个字段,则此方法比较方便

>>> D2 = {}
>>> D2[‘name‘] = ‘Bob‘
>>> D2[‘age‘]  =  40
>>> D2
{‘age‘: 40, ‘name‘: ‘Bob‘}

方法三:

#关键字形式,代码比较少,但键必须为字符串型。常用于函数赋值

>>> D3 = dict(name=‘Bob‘,age=45)
>>> D3
{‘age‘: 45, ‘name‘: ‘Bob‘}

方法四:

#如果需要将键和值逐步建成序列,则这种方式比较有用,常与zip函数一起使用
>>> D4 = dict([(‘name‘,‘Bob‘),(‘age‘,40)])
>>> D4
{‘age‘: 40, ‘name‘: ‘Bob‘}

方法五:

#如果键的值都相同的话,用这种方式比较好,并可以用fromkeys来初始化

>>> D5 = dict.fromkeys([‘A‘,‘B‘],0)
>>> D5
{‘A‘: 0, ‘B‘: 0}

字典接口

Python扩展程序提供了和字典类似的接口,字符串的值都通过键来读取。例如:

>>> import anydbm                       #导入模块,shelve也相似
>>> file = anydbm.open(‘test.db‘,‘n‘)   #保存的文件test.db, 
>>> file[‘name‘] = ‘Bruce Li‘           #存储键为name的数据
>>> file[‘jobs‘] = ‘writer/fighter/poet‘#存储键为jobs的数据
>>> file[‘ages‘] = ‘40‘                 #存储键为ages的数据
>>> data  = file[‘jobs‘].split(‘/‘)[1]  #读取键为jobs中数据
>>> print data                          #只能存储String或None型数据
fighter

#以下是cgi模块的接口,也是字典中映射的例子

>>> import cgi
>>> form  = cgi.FieldStorage()          #来自data中的参数
>>> if form.has_key(‘name‘):
...   showReply(‘Hello,‘ + form[‘name‘].value)

单个元素的元祖

>>> t1 = (0); type(t1)     #整数
<type ‘int‘>
>>> t1 = (0,); type(t1)    #单个元素的元祖
<type ‘tuple‘>

#下面两种方式是一样的,第一种方式经常用于字符串格式化输出

>>> t2 = (0,‘Hello‘,3.14)  #也用于函数传递实参
>>> t2 =  0,‘Hello‘,3.14   #最好统一用上()

元祖排序

#因为元祖不提供排序方法,所以要先转为列表

>>> T = (‘cc‘,‘aa‘,‘dd‘,‘bb‘)
>>> L = list(T)           #转为列表
>>> L
[‘cc‘, ‘aa‘, ‘dd‘, ‘bb‘]
>>> L.sort()              #再对列表排序
>>> L
[‘aa‘, ‘bb‘, ‘cc‘, ‘dd‘]
>>> id(T)                 #查看内存中的ID号
48151032L
>>> T = tuple(L)
>>> T
(‘aa‘, ‘bb‘, ‘cc‘, ‘dd‘)
>>> id(T)                 #ID号码已经发生了改变,也就是生成了新的对象
48253032L

元祖元素

NOTE:元祖顶层元素不可更改,但元祖里面的列表的值是可以修改的。如下

>>> T = (1,[2,3],4)
>>> T[1] = ‘spam‘         #顶层元素不可更改
Traceback (most recent call last):
  File "<pyshell#193>", line 1, in <module>
    T[1] = ‘spam‘
TypeError: ‘tuple‘ object does not support item assignment
>>> T[1][1] = ‘three‘    #里面子列表元素可以更改
>>> T
(1, [2, ‘three‘], 4)

在文件中存储并解析Python对象

#创建

>>> X,Y,Z = 43,44,45
>>> S     = ‘spam‘
>>> D     = {‘a‘:1,‘b‘:2}
>>> L     = [1,2,3]
>>> F     = open(‘data.txt‘,‘w‘)
>>> F.write(S+‘\n‘)
>>> F.write(‘%s,%s,%s\n‘ % (X,Y,Z))
>>> F.write(str(L)+‘$‘+str(D)+‘\n‘)
>>> F.close()

#读取

>>> bytes = open(‘data.txt‘).read()
>>> bytes         #交互模式回显
"spam\n43,44,45\n[1, 2, 3]${‘a‘: 1, ‘b‘: 2}\n"
>>> print bytes   #会解释内嵌行终止符给予用户满意的答案
spam
43,44,45
[1, 2, 3]${‘a‘: 1, ‘b‘: 2}

#解析

>>> F = open(‘data.txt‘)
>>> line = F.readline()   #读取一行
>>> line                 
‘spam\n‘

>>> line[:-1]             #用切片方式去除后面的换行符
‘spam‘
>>> line.rstrip()         #用rstip()函数去除后面的换行符
‘spam‘

#继续解析

>>> line = F.readline()    #读取下一行
>>> line                  
‘43,44,45\n‘
>>> parts = line.split(‘,‘)#以逗号来分离
>>> parts
[‘43‘, ‘44‘, ‘45\n‘]
>>> int(parts[1])          #int转为整型,会忽略换行符,空白符
44
>>> numbers = [int(P) for P in parts] #列表解析
>>> numbers
[43, 44, 45]

#最后解析

>>> line = F.readline()
>>> line
"[1, 2, 3]${‘a‘: 1, ‘b‘: 2}\n"
>>> parts = line.split(‘$‘)
>>> parts
[‘[1, 2, 3]‘, "{‘a‘: 1, ‘b‘: 2}\n"]
>>> eval(parts[0])         #将字符串转为任意object目标
[1, 2, 3]
>>> objects = [eval(P) for P in parts] #列表解析
>>> objects
[[1, 2, 3], {‘a‘: 1, ‘b‘: 2}]

用pickle存储Python的原生对象

eval可将字符串转为对象,有时功能太强大会出问题。如果想存储原生对象,又无法信赖文件的数据来源,pickle是个理想的选择。可以存储几乎Python对象的高级工具,不需要像上面那样转来转去。它是超级通用的数据格式化和解析工具.看下面例子

>>> D
{‘a‘: 1, ‘b‘: 2}
>>> F = open(‘datafile.txt‘,‘w‘)
>>> import pickle
>>> pickle.dump(D,F)         #pickle any object to file
>>> F.close()
>>>
>>> F = open(‘datafile.txt‘) 
>>> E = pickle.load(F)       #load any object from file.
>>> E
{‘a‘: 1, ‘b‘: 2}

文件中打包二进制数据的存储与解析

struct模块能够构造并解析打包的二进制数据,它是另一个数据转换工具,能够把文件中的字符串解读为二进制数据.

>>> F = open(‘data.bin‘,‘wb‘)                    #Open binary output file
>>> import struct
>>> bytes = struct.pack(‘>i4sh‘,7,‘spam‘,8)      #Make packed binary file
>>> bytes
‘\x00\x00\x00\x07spam\x00\x08‘
>>> F.write(bytes)                               #Write byte string
>>> F.close()


>>> F = open(‘data.bin‘,‘rb‘)
>>> data = http://www.mamicode.com/F.read() #Get packed binary data
>>> data
‘\x00\x00\x00\x07spam\x00\x08‘
>>> values = struct.unpack(‘>i4sh‘,data)         #Convert to Python Objects
>>> values
(7, ‘spam‘, 8)

对象的灵活性

1. 列表,字典和元祖可以包含任何种类的对象

2. 列表,字典和元祖可以任意嵌套

3. 列表和字典可以动态扩大和缩小

拷贝

1. L[:]能够复制序列

2. 字典copy方法能够复制字典

3. 有些内置函数,能够生产拷贝.比如说list(L)

4. copy标准库模块能够生产完整拷贝

>>> L = [1,2,3]
>>> A = L[:]
>>> D = {‘a‘:1,‘b‘:2}
>>> B = D.copy()

>>> A[1]=‘Ni‘
>>> B[‘c‘]=‘spam‘
>>> L,D
([1, 2, 3], {‘a‘: 1, ‘b‘: 2})
>>> A,B
([1, ‘Ni‘, 3], {‘a‘: 1, ‘c‘: ‘spam‘, ‘b‘: 2})

#所以复杂点的例子来说:

>>> X = [1,2,3]
>>> L = [‘a‘,X[:],‘b‘]        #嵌套拷贝X的对象
>>> D = {‘x‘:X[:],‘y‘:2}
>>> X[1] = ‘two‘              #这样的话X做的任何修改只会影响自身
>>> L,D
([‘a‘, [1, 2, 3], ‘b‘], {‘y‘: 2, ‘x‘: [1, 2, 3]})

#拷贝需要注意的是: 无条件值的分片以及字典copy方法只能做顶层复制。如果需要一个深层次嵌套的数据结构的完整的,完全独立的数据结构。需要用copy模块 X = copy.deepcopy(Y) 能递归地遍历对象来复制它们所有的组成部分。这种情况比较少见,一般来说copy就可以了。

类型测试

>>> isinstance([1],list)       #一般建议使用此种类型做类型测试
True
>>> type([1]) == list
True
>>> type([1]) == type([])
True

重复增加层次深度

>>> L = [7,8]
>>> X = L*2
>>> Y = [L]*2
>>> X;Y
[7, 8, 7, 8]
[[7, 8], [7, 8]]
>>> L[0]=1         #修改列表中某个元素的值
>>> X;Y            #Y的值会发生改变
[7, 8, 7, 8]
[[1, 8], [1, 8]]


>>> X = L[:]*2     #拷贝
>>> Y = [L[:]]*2
>>> X;Y            #值都不变
[7, 8, 7, 8]
[[7, 8], [7, 8]]

不可变类型不可以在原处修改

>>> T = (1,2,3)
>>> T[2] = 4      #报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ‘tuple‘ object does not support item assignment
>>> T = T[:2] + (4,) #但可以通过切片,合并等方法来处理
>>> T
(1, 2, 4)

好处是: 当程序处理元祖时,不会报上面的错,而影响程序运行.


L[:0] 为空 ‘‘  


程序一些规则

1. 最好四个空格

2. if (x>y): print x   #()最好不要用,这是类C语言风格

3. a = 1; b = 2; print a+b;  #最好不用分号;

3. 跨越多行最好用下面这几种方式(){}[],不要用\从程序的可读性来说:

>>> if (A == 1 and
...     B == 2 and
...     C == 3):
...   print ‘spam‘*3
...
spamspamspam

>>> mylist = [1,
...           2,
...           3,
...           4]
>>> mylist

#尽管这种方式也支持,可维护性差也很脆弱

>>> A,B,C,D = 1,2,3,4
>>> X = A + B + \      #这是一种类似于C语言的风格,最好不用
...     C + D
>>>
>>> X
10


在Python中else可以和if结合,也可以和try,while,for来结合使用.

#多行放一行,必须有;作为语句结尾

#且只能是简单语句:比如说赋值语句,打印和函数调用

>>> x,y,z = 1,2,3; total(x,y,z)
4
>>> a = 1; b = 2; print a + b
3

Python中常用赋值语句

>>> spam = ‘SPAM‘               #基本形式
>>> spam,ham = ‘SPAM‘,‘HAM‘     #元祖赋值运算
>>> [spam,ham] = [‘SPAM‘,‘HAM‘]  #列表赋值运算

#注意下这种赋值方式,比较新颖与特殊

>>> L = [1,2,3,4]
>>> L[len(L):] = [5,6]  
>>> L
[1, 2, 3, 4, 5, 6]
>>> a,b,c,d    = ‘SPAM‘          #列表赋值运算,通用性, a=‘S‘,b=‘P‘...
>>> spam = ham = ‘lunch‘        #多目标赋值运算

相当于下面:

>>> a = ‘SPAM‘
>>> b = a
>>> c = b

多目标赋值注意共享引用问题

#为整数

>>> a = b = 0   
>>> b +=1
>>> a,b
(0, 1)

#为列表

>>> a = b = []  
>>> b.append(4)
>>> a,b
([4], [4])

#其矫正

>>> a = []
>>> b = []
>>> b.append(4)
>>> a,b
([], [4])
>>> spams += 42                 #增强赋值运算spam=spam+42,输入少,执行速度快

有三个优点:

1. 程序员输入减少

2. 左侧只计算一次: 如果是X是复杂的对象表达式

X +=Y        X只计算一次

X  = X + Y   X必须计算两次,因此前者更快些

3. 优化技术会自动选择.对于支持原地运算的对象(比如说:列表),增强形式会自动执行原处修改的运算,而不是速度更慢的复制操作.
>>> X,Y = Y,X                   #X,Y值颠倒

>>> red,green,blue = range(3)   #序列分解赋值red =1,green =2,blue =3
>>> red,yellow
(0, 3)

下面是序列分解赋值简单例子,将其分解为开始和结尾两部分

>>> L = range(10)
>>> while L:
...   front,L = L[0],L[1:]
...   print front,L
...
0 [1, 2, 3, 4, 5, 6, 7, 8, 9]
1 [2, 3, 4, 5, 6, 7, 8, 9]
2 [3, 4, 5, 6, 7, 8, 9]
3 [4, 5, 6, 7, 8, 9]
4 [5, 6, 7, 8, 9]
5 [6, 7, 8, 9]
6 [7, 8, 9]
7 [8, 9]
8 [9]
9 []

增强赋值及共享引用

>>> M = [1,2]
>>> L = M
>>> M = M + [3,4] #‘+‘复制新对象
>>> M,L           #所以只有M改变,L不变
([1, 2, 3, 4], [1, 2])


>>> M = [1,2]
>>> L = M
>>> M += [3,4]    #+="在总是在原处在改动
>>> M;L           #所以ML都发生了改变
[1, 2, 3, 4]
[1, 2, 3, 4]

变量名命名规则

以_或字母开头,后面接[a-zA-Z],[0-9],_

所以下面是正确的

_spam

Spam_

spam1

下面是错误的

1spam

spam$

@#!

还要注意,不要用Python保留字,特别是在模块中,如我们可以给脚本取名and.py, my-file.py但确不可以作为包导入

>>> import and
SyntaxError: invalid syntax
>>> import my-file
SyntaxError: invalid syntax

命令惯例

_X       不会被from module import * 导入

__X__    系统定义的变量名,对解释器有特殊意义

__X      是类的本地变量,不能被外界访问

通过交互模式运行时,_X会保留最后表达式的结果

其他规则

1. 类名,首字母大写

2. 模块名小写

3. 函数名首字母小写


A < B and B !=C

A < B < C  等价于 A < B and B < C

=   表达式赋值

==  测试是否相等

表达式在原地修改

#正确的做法如下:

>>> L = [1,2]
>>> L.append(3)
>>> L
[1, 2, 3]

#错误的做法如下:

>>> L = L.append(4)  #将原地添加的值再赋给L
>>> L                #空值
>>> 

对列表调用append,sort或者reverse这类在原处修改的运算,一定是对列表做原处的修改,但这些方法在列表修改后并不会把列表返回。事实上,它们返回的是None对象。如果赋值给该变量的变量名,只会丢失该列表,而且可能在此过程中被当成垃圾回收。这是初学者常犯的错误,所以不要这么做。

Print

#sys.stdout.write具有同样的作用

>>> import sys
>>> sys.stdout.write(‘Hello,World!‘)
Hello,World!

print spam,ham             #把对象打印至sys.stdout,在元素间增加一个空格,在末尾增加换行字符

print spam,ham,            #如上,但在文本末尾没有加换行符号,想显示连续输出的效果,很有用

print >> myfile,spam,ham   #把文字传给myfile.write,而不是sys.stdout.write

>>> for i in range(4):
print i
输出结果
0
1
2
3
>>> for i in range(4):
print i,
输出结果
0 1 2 3  #输出默认有个空格

>>> myfile = file(‘myfile.txt‘,‘w‘)
>>> say    = ‘This is print >> test!‘
>>> print >> myfile, say               #将say中内容传给
>>> myfile.close()

print 和 sys.stdout关系如下:

print X

等价于

import sys

sys.stdout.write(str(X)+‘\n‘)

print >> file扩展

通过赋值sys.stdout而将打印文字重定向的技巧,在实际上非常常用。sys.stdout是个普通的文件对象,可以存储它,需要时恢复了,看下面的例子.

>>> import sys
>>> temp = sys.stdout                #存储到临时变量
>>> sys.stdout = open(‘log.txt‘,‘a‘) #重定向到一个文件
>>> print ‘spam‘                     #向文件中打印,而不是在屏幕上显示
>>> print 1,2,3
>>> sys.stdout.close()               #将输出结果从内存写入硬盘
>>> print ‘back here‘                #所以这里会报错
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    print ‘back here‘
ValueError: I/O operation on closed file
>>> sys.stdout = temp                #恢复原始流          
>>> print ‘back here‘                #重新再屏幕上显示输出
back here
>>> print open(‘log.txt‘).read()     #早期的打印结果
spam
1 2 3

鉴于这种手动保存和恢复原始输出流的方法比较复杂,增强print的扩展功能.

log = open(‘log.txt‘,‘a‘)

print >> log,x, y, z    #Print to a file-like object

print a, b, c           #Print to original stdout

>>> log = open(‘log.txt‘,‘a‘)
>>> print >> log, 1, 2, 3
>>> print >> log, 4, 5, 6
>>> log.close()
>>> print 7,8,9
7 8 9
>>> print open(‘log.txt‘).read()
1 2 3
4 5 6


这种print的扩展形式通常用于将错误信息打印到标准错误流sys.stderr,有两种方式

方法一:

>>> import sys
>>> sys.stderr.write((‘Error info:...‘)+‘\n‘)
Error info:...

方法二:
>>> print >> sys.stderr, ‘Error info:...‘
Error info:...


while:

x = ‘spam‘

while x:   #while x not empty

#等价于 while x !=‘‘ 

  print x,

  x = x[1:]

三种布尔运算

if X and Y:  如果X和Y都为真,方为真

if X or  Y:  如果X或Y为真,就是真

if not X  :  如果X为假,那就是真(表达式返回True或False)

if/else 三元表达式

Variable = A if expression else B

变量赋值: 如果条件为真的话,那么为A,条件为假的话,B

>>> a = 10
>>> b = 20
>>> V = b if b > 10 else a
>>> V
20

A = [Z,Y][bool(X)]

>>> [‘f‘,‘t‘][bool(‘‘)]     #bool(‘‘)返回0,所以取前面一个
‘f‘
>>> [‘f‘,‘t‘][bool(‘true‘)] #bool(‘true‘)返回1,所以取后面一个
‘t‘

【短路

在程序中,为防止短路现象(前面条件满足了,后面就不执行),将其赋值给临时变量

temp1,temp2 = f1(),f2()

if temp1 or temp2: ...

break,continue,pass,和循环else

break:      跳出最近所在的循环(跳过整个循环语句)

continue:   跳到最近所在的循环的开头处(来到循环的首行) 

pass:       什么事也不干,占位语句,有时也用于将来补齐代码

循环else块: 只有当循环正常离开时才会执行(也就是没有碰到break语句).

在for循环中元祖赋值

>>> T =((1,2),(3,4),(5,6),(7,8))
>>> for (a,b) in T:
...   print a,b
...
1 2
3 4
5 6
7 8

嵌套for循环

items = [2,‘Spam‘,{‘a‘:1},(4,5),[1,2],((4,5),(7,8))] #要找的目标
tests = [(4,5),3.14]                                 #测试对象

for key in tests:                                    #遍历所有的test
    for item in items:                               #遍历所有的item
        if key == item:
            print key,‘has found!‘
            break
        else:
            print key,‘not Found!‘

简单点写

for key in tests:
    if key in items:
        print key, ‘has found!‘
    else:
        print key, ‘not found!‘

输出结果:

>>> 
(4, 5) has found!
3.14 not found!

求交集

seq1 = ‘spam‘
seq2 = ‘scam‘
res  = []

for x in seq2:
    if x in seq1:
        res.append(x)
        
print res

输出结果

[‘s‘, ‘a‘, ‘m‘]

【迭代工具

for循环可用于任何可迭代工具. 可迭代工具一般包含for循环,列表解析,in成员测试,map等内置工具

下面这种方式相比较for循环迭代,速度会慢一些,因为迭代器在Python中是以C语言的速度运行的,而while循环是Python虚拟机运行Python字节码的.所以任何时候,我们把Python代码换成C代码,速度都会快些.for循环一般比while循环容易些,速度更快些.

>>> while True:
...   line = f.readline()
...   if not line: break
...   print line.upper()


对字典迭代更简洁,高效的方法

D = {‘a‘:1,‘b‘:2,‘c‘:3}

>>> for key in D:
...   print key,D[key]
...
a 1
c 3
b 2

其他迭代工具

每一种由左往右扫描对象的工具都会使用迭代协议,包括for循环,列表解析,in成员测试,map函数,及其他内置工具(sort,sum等)

#假如测试文件test.txt就下面两行

This is line 1
This is line 2

>>> uppers = [line.upper() for line in open(‘test.txt‘)]
>>> uppers
[‘THIS IS LINE 1\n‘, ‘THIS IS LINE 2\n‘, ‘\n‘]

>>> ‘This is line 2\n‘ in open(‘test.txt‘)
True

>>> sorted(open(‘test.txt‘))
[‘\n‘, ‘This is line 1\n‘, ‘This is line 2\n‘]

>>> sorted([4,3,1,2])
[1, 2, 3, 4]
>>> sum([4,3,1,2])
10
>>> any([‘spam‘,‘‘,‘ni‘])  #返回True或者False
True
>>> all([‘spam‘,‘‘,‘ni‘])  #返回True或者False
False

包括list,tuple,及join方法,甚至赋值语句,都是可迭代对象

>>> list(open(‘test.txt‘))
[‘This is line 1\n‘, ‘This is line 2\n‘, ‘\n‘]
>>> tuple(open(‘test.txt‘))
(‘This is line 1\n‘, ‘This is line 2\n‘, ‘\n‘)
>>> ‘&&‘.join(open(‘test.txt‘))
‘This is line 1\n&&This is line 2\n&&\n‘
>>> a,b,c = open(‘test.txt‘)
>>> a,b,c
(‘This is line 1\n‘, ‘This is line 2\n‘, ‘\n‘)

range,xrange

range: 一次性将所有的索引放入列表

range支持反向迭代. 

>>> range(5,-5,-1)
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]

xrange: 没有速度优势,但如果有大数据,则有空间优势.在Python 3.0里面,xrange会消失,这一功能会放到range里面,range会变成迭代器对象,支持迭代协议,一次产生一个对象,而不是一次产生全部放到列表中.

>>> for i in range(3):
...   print ‘%06d‘ % (i),‘Pythons‘
...
000000 Pythons
000001 Pythons
000002 Pythons

简单的例子,如果要迭代,取出字符串中的每个元素

方法一:  这种应该是最简单的

>>> X = ‘spam‘
>>> for i in X:
...   print i,
...
s p a m

方法二:

>>> i = 0
>>> X = ‘spam‘
>>> while i < len(X):
...   print X[i],
...   i += 1
...
s p a m

方法三:

>>> X = ‘spam‘
>>> for i in range(len(X)):
...   print X[i],
...
s p a m

如果隔开来取,可以这样:

>>> S = ‘ABCDEFGHIJK‘
>>> for i in S[::2]:
...   print i,
...
A C E G I K

或者:

>>> S = ‘ABCDEFGHIJK‘
>>> for i in range(0,len(S),2):
...   print S[i],
...
A C E G I K

但如果要修改列表的话:

#第一种方法就不行了.

>>> L = [1,2,3,4]
>>> for x in L:
...   x += 1
...
>>> L
[1, 2, 3, 4]

#必须用第二种方法

>>> L = [1,2,3,4]
>>> for i in range(len(L)):
...   L[i] +=1
...
>>> L
[2, 3, 4, 5]

#或者用第三种方法

>>> L = [1,2,3,4]
>>> i = 0
>>> while i < len(L):
...   L[i] += 1
...   i += 1
...
>>> L
[2, 3, 4, 5]

当然

[x+1 for x in [1,2,3,4]] 这种列表解析更简单些

并行遍历,zip

内置的range允许我们在for循环中以非完备的方式遍历序列,内置的的zip函数也可以让我们使用for循环来并行使用多个序列,假如要计算两个坐标的和值

>>> L = [1,2,3]
>>> L1 = [1,2,3]
>>> L2 = [4,5,6]
>>> zip(L1,L2)           #使用zip创建配对后的元祖列表
[(1, 4), (2, 5), (3, 6)]
>>> for (x,y) in zip(L1,L2):
...   print x,y,‘==>‘,x+y
...
1 4 ==> 5
2 5 ==> 7
3 6 ==> 9

#ZIP函数支持两个以上的参数

>>> T1,T2,T3 = (1,2),(3,4),(5,6)
>>> zip(T1,T2,T3)
[(1, 3, 5), (2, 4, 6)]

#而且以最小长度的为准.

>>> S1 = ‘ABC‘
>>> S2 = ‘XYZ123‘ #123超过部分, 不在元祖队列
>>> zip(S1,S2)
[(‘A‘, ‘X‘), (‘B‘, ‘Y‘), (‘C‘, ‘Z‘)]

ZIP创建字典

像下面这样一个字典

>>> D1 = {‘spam‘:1,‘eggs‘:3,‘cake‘:5}
>>> D1
{‘cake‘: 5, ‘eggs‘: 3, ‘spam‘: 1}

可以通过下面方式赋值来建立 

>>> D1 = {}
>>> D1[‘spam‘] = 1
>>> D1[‘eggs‘] = 3
>>> D1[‘cake‘] = 5
>>> D1
{‘cake‘: 5, ‘eggs‘: 3, ‘spam‘: 1}

如果是通过程序获得keys,values的列表,比如说

>>> keys = [‘spam‘,‘eggs‘,‘cake‘]
>>> vals = [1     , 3    ,5     ]

那么要如何建立字典呢,方法很简单

方法一:

>>> D2 = {}
>>> for k,v in zip(keys,vals):
...   D2[k] = v
...
>>> D2
{‘cake‘: 5, ‘eggs‘: 3, ‘spam‘: 1}

方法二:
>>> D3   = dict(zip(keys,vals))
>>> D3
{‘cake‘: 5, ‘eggs‘: 3, ‘spam‘: 1}

产生偏移和元素:enumerate

一般做法:

>>> S = ‘spam‘
>>> offset = 0
>>> for item in S:
...   print item,‘offset is:‘, offset
...   offset += 1
...
s offset is: 0
p offset is: 1
a offset is: 2
m offset is: 3

#enumerate函数实现

>>> S = ‘spam‘
>>> for (offset,item) in enumerate(S):   #注意offset,item顺序
...   print item,‘appears in place‘, offset
...
s appears in place 0
p appears in place 1
a appears in place 2
m appears in place 3

#enumerate函数会自动产生迭代器,有next()方法,每次遍历时会产生(index,value)的元祖列表

>>> E = enumerate(S)
>>> E.next()
(0, ‘s‘)
>>> E.next()
(1, ‘p‘)
>>> E.next()
(2, ‘a‘)
>>> E.next()
(3, ‘m‘)
>>> E.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

#又一个例子,结合列表解析, s*0,p*1,a*2...

>>> [c* i for (i,c) in enumerate(S)]
[‘‘, ‘p‘, ‘aa‘, ‘mmm‘]

列表解析基础

如果要实现在[1,2,3,4]这个列表上每个元素加10,可以这样

>>> L = [1,2,3,4]
>>> for i in range(len(L)):
...   L[i] += 10
...

>>> L
[11, 12, 13, 14]

或者

>>> L = [1,2,3,4]
>>> res = []
>>> for x in L:
...   res.append(x+10)
...
>>> res
[11, 12, 13, 14]

没有必要用列表解析,但列表解析有以下好处

[x+10 for x in [1,2,3,4]]

1. 代码简洁

2. 速度快,常常快2倍左右.因为列表解析的迭代在解释器上是以C语言的速度执行的,而不是手动编写的Python代码.


对文件使用列表解析

#常规做法,这样做,每个后面会有换行符,挺碍事的.

>>> f = open(‘test.txt‘)
>>> lines = f.readlines()
>>> lines
[‘This is line 1\n‘, ‘This is line 2\n‘]

#列表解析,可以这样做

>>> lines = [line.rstrip() for line in lines]
>>> lines
[‘This is line 1‘, ‘This is line 2‘]

#设置可以不用中间变量,直接在open().readlines()写

>>> lines = [line.rstrip() for line in open(‘test.txt‘)]
>>> lines
[‘This is line 1‘, ‘This is line 2‘]

NOTE: 对于大型文件,列表解析的速度尤其明显


【扩展列表解析语法】

列表解析中嵌套for循环再结合if语句来过滤条件,这是个非常有用的扩展

假如要将test.txt文件中,首字母为P的

Python
Perl
Java
Shell

方法一: 常规做法

>>> f   = open(‘test.txt‘)
>>> res = []

>>> while True:
...   line = f.readline()
...   if not line: break
...   if line[0] == ‘P‘:
...     res.append(line.rstrip())
...
>>> res
[‘Python‘, ‘Perl‘]

或者

res = []

>>> for line in open(‘test.txt‘):
...   if line[0] == ‘P‘:
...     res.append(line.rstrip())
...
>>> res
[‘Python‘, ‘Perl‘]

方法二: 列表解析

#只需要一行代码

>>> lines = [line.rstrip() for line in open(‘test.txt‘) if line[0] == ‘P‘]
>>> lines
[‘Python‘, ‘Perl‘]


【dir函数】

dir函数: 抓取对象内所有属性的简单方法,

如果是需要导入的某个模块的话,可以这样使用.

>>> import sys
>>> dir(sys)
[‘__displayhook__‘, ‘__doc__‘, ‘__excepthook__‘, ‘__name__‘,......,‘version_info‘, ‘warnoptions‘, ‘winver‘]

如果是系统某个类型的话,可以这样使用:

>>> dir(list)
[‘__add__‘, ‘__class__‘..‘append‘, ‘count‘, ‘extend‘, ‘index‘, ‘insert‘, ‘pop‘, ‘remove‘, ‘reverse‘, ‘sort‘]

>>> dir(dict)
[‘clear‘, ‘copy‘, ‘fromkeys‘, ‘get‘, ‘has_key‘, ‘items‘, ‘iteritems‘, ‘iterkeys‘, ‘itervalues‘, ‘keys‘, ‘pop‘, ‘popitem‘, ‘setdefault‘, ‘update‘, ‘values‘, ‘viewitems‘, ‘viewkeys‘, ‘viewvalues‘]

>>> dir(int)

>>> dir(str)

>>> dir(file)

>>> dir(tuple)

或者像下面这样也行

>>> dir(0)

>>> dir(‘‘)

>>> dir(open(‘test.txt‘))

>>> dir({})

>>> dir([])

>>> dir(())


Python 点滴 I