示例2.1/2.2/2.3 把一个字符串变成Unicode码位的列表
普通方法
symbols='!@#$%^'
codes=[]
for symbol in symbols:#使用append()方法向空列表添加元素
codes.append(ord(symbol))
print(codes)
输出结果:
使用列表推导的方法
symbols='!@#$%^'
codes=[ord(symbol)for symbol in symbols]#列表推导的固定写法,看起来是不是更简洁?
print(codes)
输出结果:
使用filter和map创建
alphabet='abcdefghijklmnopqrstuvwxyz'
#beyond_ascii=[ord(s) for s in alphabet if ord(s)<100]
beyond_ascii=list(filter(lambda s:s<100,map(ord,alphabet)))#map根据指定函数做映射,返回迭代器。fillter用于过滤序列
print(beyond_ascii)
输出结果:
示例2.4 使用列表推导计算笛卡尔积
注:笛卡尔积是一个列表,列表里的元素是由输入的可迭代类型的元素对构成的元组,因此笛卡尔积列表的长度等于输入各变量长度的乘积。
colors=['black','white']
sizes=['S','M','L']
tshits=[(color,size) for color in colors \
for size in sizes]#\是续行符,在[],(),{}中的换行可以省略
print(tshits)#得到的结果先以颜色排列,再以尺码排列
tshits2=[(size,color) for size in sizes
for color in colors]
print(tshits2)#得到的结果先以尺码排列,再以颜色排列
输出结果:
示例2.5 用生成器表达式初始化元组和数组
生成器类似列表推导
import array
alphabet='abcdefghijklmnopqrstuvwxyz'
t=tuple(ord(s) for s in alphabet)
print(t)
a=array.array('I',(ord(s) for s in alphabet))
print(a)
输出结果:
示例2.6 用生成器表达式计算笛卡尔积
colors=['black','white']
sizes=['S','M','L']
for tshirt in ('%s %s' % (c,s) for c in colors for s in sizes):#生成器表达式只会逐个产生元素
print(tshirt)
输出结果:
示例2.7 把元组用作记录
lax_coordinates=(33.9425,-118.408056)
city,year,pop,chg,area=('Tokyo',2003,32450,0.66,8014)
traveler_ids=[('USA','31195855'),('BRA','CE342567'),('ESP','XDA205856')]
for passport in sorted(traveler_ids):#在迭代时,passport变量被绑定到每一个元组上
print('%s/%s' %passport)# %格式运算符能被匹配到对应的元组元素上
for contry,_ in traveler_ids:#for循环分别提取元组里的元素,叫做拆包。元组中第二个元素没有使用,可以使用占位符‘_’
print(contry)
输出结果:
示例2.8 嵌套元组拆包
metro_areas=[
('Tokyo','JP',36.993,(35.689722,139.691667)),#每个元组有4个元素,其中最后一个是一对坐标
('Delhi NCR','IN',21.935,(28.613889,77.208889)),
('Mexico City','MX',20.142,(19.433333,-99.13333)),
('New York-Newark','US',20.104,(40.808611,-74.020386)),
('Sao Paulo','BR',19.649,(-23.547778,-46.635833))
]
print('{:15} | {:^9} | {:^9}'.format('','lat.','long.'))
fmt='{:15} | {:^9} | {:^9}'
for name,cc,pop,(lat,lon) in metro_areas:#可以把元组最后一个元素拆包到由变量构成的元组中
if lon<=0:#限制输出西半球的城市
print(fmt.format(name,lat,lon))
输出结果:
示例2.9/2.10 具名元组
具名元组可以用来构建一个带字段名的元组和一个有名字的类
from collections import namedtuple
City=namedtuple('City','name country population coordinates')#具名元组有两个参数,一个是类名,另一个是类的各个字段的名字。
tokyo=City('Tokyo','JP',36.933,(35.689722,139.691667))
print(tokyo)
print(tokyo.population)#可以通过字段名或者位置来获取某个字段的信息
print(tokyo[3])
print(City._fields)#_fields属性是一个包含这个类所有字段名称的元组
LatLong=namedtuple('LatLong','lat long')
delhi_data=('Delhi NCR','IN',21.935,LatLong(28.613889,77.208889))
delhi=City._make(delhi_data)#通过接受一个可迭代对象来生成这个类的一个实例,它的作用跟City(*delhi_data)一样
print(delhi._asdict())#把具名元组以collections.OrderedDict的形式返回
输出结果:
示例2.11 对对象进行切片
用slice对seq[start:stop:step]进行切片,可以给切片命名
salarys='''
姓名 基础工资 绩效工资 出勤 工龄工资 五险一金 扣税 实发
老江 8000 6000 1000 200 -1200-400 13600
老谢 7800 6000 1000 200 -1200-400 13400
瓜皮昊 7600 6000 1000 200 -1200-400 13200
冬瓜李呢 7000 6000 1000 200 -1200-400 12600
'''
name=slice(0,5)
base_sal=slice(5,10)
bonus=slice(10,15)
commutting=slice(15,20)
time_bonus=slice(20,25)
ensurance=slice(25,30)
tax=slice(30,35)
totle=slice(35,None)
line_items=salarys.split('\n')[2:]
for item in line_items:
print(item[name],item[totle])
输出结果:
示例2.12/2.13 建立列表组成的列表
模拟3*3的方块矩阵,创建一个包含3个列表的列表
#示例2.12
board=[['_']*3for i in range(3)]#建立一个包含3个列表的列表,被包含的三个列表各自有三个元素。
print(board)
board[1][2]='x'#把第一行第二列元素标记为x
print(board)
输出结果:
含有3个指向同一对象的引用的列表是毫无用处的
#示例2.13
weird__board=[['_']*3]*3#外面的列表其实包含三个指向同一个列表的引用
print(weird__board)
weird__board[1][2]='x'#一旦我们试图标记某个元素,就立马暴露了列表内三个引用指向同一对象的事实
print(weird__board)
输出结果:
示例2.13犯的错误本质和下列代码一致
row=['_']*3
borad=[]
for i in range(3):
borad.append(row)#向空列表加入了同一个行对象(row)三次到游戏板(board)
print(borad)
borad[1][2]='x'
print(borad)
输出结果:
相反,示例2.12中的做法与下列等同
board=[]
for i in range(3):
row=['_']*3#每次循环都新建了一个列表,作为新的一行(row)加入到游戏板(board)
board.append(row)
print(board)
board[0][0]='a'
print(board)
输出结果:
bisect二分查找模块
示例2.17 在有序序列中用bisect查找某个元素的插入位置
import bisect#bisect模块主要包含两个主要函数,bisect和insort,这两个函数都利用二分查找算法来在有序序列中查找或插入元素
import sys#sys是一个与当前程序运行之外的系统环境打交道的模块
HAYSTACK=[1,4,5,6,8,12,15,20,21,23,23,26,29,30]
NEEDLES=[0,1,2,5,8,10,22,23,29,30,31]
ROW_FMT='{0:2d} @ {1:2d} {2}{0:<2d}'
def demo(bisect_fn):
for needle in reversed(NEEDLES):
position=bisect_fn(HAYSTACK,needle)#用特定的bisect函数来计算元素应该出现的位置
offset=position *' |'#利用该位置算出需要几个分隔符号
print(ROW_FMT.format(needle,position,offset))#按格式打印元素和应该出现的位置
if __name__=='__main__':#如果当前模块时被直接执行,__name__的值就是__main__,条件判断的结果为True,“if __name__=='__main__':”下面的代码块就会被执行。
if sys.argv[-1]=='left':#选择是bisect_left函数还是bisect_right函数
biset_fn=bisect.bisect_left
else:
bisect_fn=bisect.bisect
print('DEMO:',bisect_fn.__name__)#打印选定的函数
print('haystack ->',' '.join('%2d' % n for n in HAYSTACK))
demo(bisect_fn)
输出结果:
bisect函数是bisect_right函数的别名,它还有一个姊妹函数叫bisect_left。区别在于遇到相同值时是左插入还是右插入。
示例2.18 根据一个分数,找到他所对应的成绩
import bisect
def grade(score,breakpoints=[60,70,80,90],grades='FDCBA'):
i=bisect.bisect(breakpoints,score)#获得插入位置的index
return grades[i]
l=[grade(score) for score in [33,99,77,70,89,90,100]]
print(l)
输出结果:
示例2.19 insort可以保持有序序列的顺序插入
import bisect
import random
SIZE=7
random.seed(1729)
my_list=[]
for i in range(SIZE):
new_item=random.randrange(SIZE*2)#生成随机数
bisect.insort(my_list,new_item)
print('%2d ->' % new_item,my_list)
输出结果:
某些情况下可以替换列表的数据类型
示例2.20 一个浮点数类型的创建、存入文件和从文件中读取的过程
from array import array
from random import random
floats=array('d',(random() for i in range(10**7)))#创建数组需要两个参数,类型码和数据
print(floats[-1])#查看数组的最后一个元素
fp=open('floats.bin','wb')
floats.tofile(fp)
fp.close()
floats2=array('d')#新建一个双精度浮点型空数组
fp=open('floats.bin','rb')
floats2.fromfile(fp,10**7)#把1000万个浮点数从二进制文件中读取出来
fp.close()
print(floats2[-1])#查看新数组的最后一个元素
print(floats2==floats)#检查两个数组是否完全一样
输出结果:
示例2.21 (内存视图)通过改变数组中的一个字节来更新数组中某个元素的值
import array
numbers=array.array('h',[-2,-1,0,1,2])
memv=memoryview(numbers)#利用含有5个短整型有符号整数(类型码'h')的数组创建一个memoryview
print(len(memv))
print(memv[0])#memv中的5个元素与数组中的没有区别
memv_oct=memv.cast('B')#创建一个memv_oct,把memv里的内容转换成无符号字符('B'类型)
print(memv_oct.tolist())#以列表形式查看memv_oct的内容
memv_oct[5]=4#把位于位置5的字节赋值成4
print(numbers)
输出结果:
示例2.23 使用双向队列
from collections import deque
dq=deque(range(10),maxlen=10)#maxlen是一个可选参数,代表这个队列可以容纳的元素的数量,一旦设定不能更改
print(dq)
dq.rotate(3)#队列的旋转操作接收一个参数n,当n>0时,队列最右边的n个元素会被移到队列的左边。当n<0时,最左边的n个元素会被移到右边
print(dq)
dq.rotate(-4)
print(dq)
dq.appendleft(-1)#对已满的队列进行头添加时,尾部的元素会被删除
print(dq)
dq.extend([11,22,33])
print(dq)
dq.extendleft([10,20,30,40])#extendleft(iter)方法会把迭代器里的元素逐个添加到双向队列的左边,因此迭代器里的元素会逆序的出现在队列中
print(dq)
输出结果:
双向队列deque常用函数