《流畅的python》阅读笔记 - 第二章:数据结构

内置序列类型概览

在《算法》一书中,数组,链表称为数据结构.
,队列,称为数据类型,在《流畅的python》第二章中,首先介绍了python几种内置(即不用程序员实现,python自带)的序列类型:
在这里插入图片描述《流畅的python》中列图示了可变和不可变序列的差异,在我看来,可变数据多了一些可以操作数据的方法,增删,修改值等.list列表是最基础的可变序列,类似C语言的数组,只是它更灵活一些,它是容器序列,存放的元素数据类型可以是不一样的.

列表推导和生成器表达式

列表可以用列表推导这种方法来快速构造一个列表,而生成器表达式可以创建其它任何类型的序列.

symbols = '!@#$%^^&*()_+'
codes = [ord(symbol) for symbol in symbols]
print(codes)

ord(parm)将parm转换成数值,这个数值是它对应的的Unicode码位,这里参数是一个字符,所以转换后是一个列表,user_list = [func() for n in N] 这是一个列表生成器,它方便的生成一个列表.第一章初有涉及.其中列表中的 n 是一个局部变量,所以不用担心修改到其他变量.详细见《流畅的python》 2.2.1

如果把列表推导的[]改为 (),则列表推导变为生成器表达式:

tuple(ord(symbol) for symbol in symbols)

用法类似,区别在于,列表推导会建立一个完整的列表,而生成器会一个一个产出,程序可以逐个操作它们.我能想到的用法是,对于一个列表,生成到某一个值以后,程序就不需要继续生成了,那么生成器表达式是更好的.但是我并没有通过代码验证.

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-6),它的输出为:

black S
black M
black L
white S
white M
white L

我做了一个小练习,加入一行判断的代码,让其打印出white S后就不再输出:

colors = ['black','white']
sizes = ['S','M','L']
for tshirt in ('%s %s'%(c ,s) for c in colors for s in sizes):
    print(tshirt[:5],tshirt[-1])
    if tshirt[:5] == 'white' and tshirt[-1] == 'S':
        break

它的输出为:

black S
black M
black L
white S

可以看到,少打印的最后两行,for循环下print(tshirt[:5],tshirt[-1])无法用c,s来表示,只能用tshirt,我想是前文作用域的原因,如果你不理解中括号里面的:5-1,请查看python列表相关的内容.

元祖不仅仅是不可变的列表 这小节指出:元组不只是存放一个值,还存放了这个值的位置,.2.25小节有具体的对比,不过我依旧没有看出来元组和不可以被改变的列表有什么不同…

具名元组指的是元素拥有名字,即是可以给元组里面各个元素命名,然后通过其名字来访问它

from collections import namedtuple
City = namedtuple('City','name country population coordinates')
tokyo = City('Tokyo','JP',36.993,(35.689722,139.691667))
print(tokyo)
print(tokyo.name)

它的输出:

City(name='Tokyo', country='JP', population=36.993, coordinates=(35.689722, 139.691667))
Tokyo

City = namedtuple('City','name country population coordinates')看起来有点奇怪,它的第二个参数不是第一章那样的元组,而是字符串,测试效果来看,使用字符串也是可以的,只要一一对于即可,书中指明:“后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串.”
print(tokyo.name) 通过名字来访问数组的元素,这样比通过位置来访问更具可读性
此外,还可以使用 namedtuple._asdict()格式化输出具名元组:

from collections import namedtuple
City = namedtuple('City','name country population coordinates')
tokyo = City('Tokyo','JP',36.993,(35.689722,139.691667))
print(tokyo._asdict())

它的输出:

{'name': 'Tokyo', 'country': 'JP', 'population': 36.993, 'coordinates': (35.689722, 139.691667)}

切片

一个长度为N(N>x)的列表,user_list[:x],```user_list[x:]``,第一个是[0,x),第二个是[x,N-1],这就是切片和区间会忽略最后一个元素的原因.

序列的增量赋值

l = [1,2,3]  #一个列表 l
t = (1,2,3)  #一个元组 t

l *= 2       #每一个元素都乘2
t *= 2       #每一个元素都乘2

print(l,t)      

它的输出:

[1, 2, 3, 1, 2, 3] (1, 2, 3, 1, 2, 3)

在这段程序中,每个序列都被扩展了,但是如果你使用id()来观察它们各自的位置信息,可以发现,列表的首地址没有改变,但是元组的首地址已经改变了.所以对元组的操作会更加消耗时间.本小节还提到了列表 += 的谜题,在平时中避免使用即可.

list.sort方法和内置函数sorted

list.sortlist.sorted都是排序列表(默认小在前,大在后,reverse 参数可以改为 True,这样就会反过来排序),区别在于,sort() 是原地排序,使用这个方法后,list列表的值会改变,它会放回None,而sorted()则在不改变原来列表的情况下,新建预一个排序后的列表,可以使用python的列表推导来生成一个随机的列表,并测试他们的排序,sorted()可自行实现:

import random

l = [random.randint(0,100) for i in range(20)] #在0-99之间生成20个随机数,存放在 l 中
print("初始值",l)
l.sort()
print("排序后",l)

输出:

初始值 [25, 39, 35, 8, 37, 60, 43, 44, 84, 48, 73, 11, 47, 46, 26, 66, 85, 58, 68, 74]
排序后 [8, 11, 25, 26, 35, 37, 39, 43, 44, 46, 47, 48, 58, 60, 66, 68, 73, 74, 84, 85]

当列表不是首选时

列表比较灵活,但是如果数值是统一的,直接使用数组会更加的高效,如果需要频繁的对队列先进先出处理,qeque则更加合适,所以程序员可以了解各种数据结构的优缺点,在设计程序的时候可以做到更优.
array.array 元素只能是数字,没有列表灵活但是更加的高效,包含.pop(),.insert,.exted,以及操作文件的.frombytes(),.tofile.pickle模块的pickle.dump()方法接近array.tofile(),不过他可以处理几乎所有的内置数据类型.在Python 3.4版本,数组类型就不支持就地排序了,需要新建立一个数组来存放排序后的值.

numbers = array.array('h',[-2,-1,0,1,2])  #创建一个数组

这里数组又2个参数,第一个h表示用 int 类型创建数组:

CodeC TypePython TypeMin bytes
bsigned charint1
Bunsigned charint1
uPy_UNICODEUnicode2
hsignedshort int2
Hunsigned shortint2
isigned intint2
Iunsigned intint2
lsigned longint4
Lunsigned longint4
ffloatfloat4
ddoublefloat8

表格参考:Python Array

矩阵的计算,建议使用 NumPySciPy库.注意,这2个库都是第三方库,所以你在使用以下代码,需要确保已经安装了Numpy库.

imoprt numpy

如果使用list来做队列是可以的,但是collections.deque这个类更加的合适,可以理解这个类是针对队列设计的.‘‘collections.deque 类(双向队列)是一个线程安全、可以快速从两端添加或者删除元素的数据类型。’’

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值