做海淘网站赚钱吗,怀化网站建设有哪些,淘宝美工做倒计时图片网站,建设电子商务网站要多少钱一、介绍
ABC语言时一个致力于为初学者设计编程环境的长达十年的研究项目。 Python也从ABC那里继承了用统一的风格去处理序列数据这一特点。不管是哪种数据结构#xff0c;字符串、列表、字节序列、数组、XML元素#xff0c;抑或是数据库查询结果#xff0c;它们都共用一套…一、介绍
ABC语言时一个致力于为初学者设计编程环境的长达十年的研究项目。 Python也从ABC那里继承了用统一的风格去处理序列数据这一特点。不管是哪种数据结构字符串、列表、字节序列、数组、XML元素抑或是数据库查询结果它们都共用一套丰富的操作迭代、切片、排序还有拼接。
二、Python内置序列类型概览
1、按照存放内容的类型分类
1)容器序列存放的是它们所包含的任意类型的对象的引用例如list、tuple和collections.deque。 2)扁平序列存放的是值而不是引用。换句话说扁平序列其实是一段连续的内存空间 例如str、bytes、bytearray、memoryview和array.array。
2、按照内容能否被修改来分类
1)可变序列(MutableSequence)例如list、bytearray、array.array、collections.deque和memoryview。 2)不可变序列(Sequence)例如tuple、str和bytes 虽然内置的序列类型并不是直接从Sequence和MutableSequence这两个抽象基类Abstract Base ClassABC继承而来的但是了解这些基类可以帮助我们总结出那些完整的序列类型包含了哪些功能。
三、列表推导和生成器表达式
1、列表推导list comprehension
1.1 基本语法
symbolsabcdefg
codes [ord(s) for s in symbols]
codes
Out[3]: [97, 98, 99, 100, 101, 102, 103]1.2 列表推导同filter和map的比较
filter和map合起来能做的事情列表推导也可以做而且还不需要借助难以理解和阅读的lambda表达式。 比如我们只想保留编码大于100 的字符
# map实现
beyond_ascii list(filter(lambda c: c100, map(ord, symbols)))
beyond_ascii
Out[5]: [101, 102, 103]
# 列表推导实现
beyond_ascii [ord(s) for s in symbols if ord(s)100]
beyond_ascii
Out[7]: [101, 102, 103]1.3生成器表达式
虽然也可以用列表推导来初始化元组、数组或其他序列类型但是生成器表达式是更好的选择。这是因为生成器表达式背后遵守了迭代器协议可以逐个地产出元素而不是先建立一个完整的列表然后再把这个列表传递到某个构造函数里。前面那种方式显然能够节省内存。
beyond_ascii list(ord(s) for s in symbols if ord(s)100)
beyond_ascii
Out[9]: [101, 102, 103]四、tuple不只是不可变列表
1、tuple除了用作不可变的列表
它还可以用于没有字段名的记录。鉴于后者常常被忽略我们先来看看元组作为记录的功用。 如果只把元组理解为不可变的列表那其他信息——它所含有的元素的总数和它们的位置——似乎就变得可有可无。但是如果把元组当作一些字段的集合那么数量和位置信息就变得非常重要
city,year,pop,chg,area(Tokyo, 2003, 32450, 0.66, 8014)traveler_ids [(USA, 31195855), (BRA, CE342567)]
for passport in traveler_ids:print(%s/%s%(passport))
USA/31195855
BRA/CE3425672、元组拆包
上面示例中我们把元组(‘Tokyo’, 2003, 32450, 0.66, 8014)里的元素分别赋值给变量city、year、pop、chg和area而这所有的赋值我们只用一行声明就写完了。同样在后面一行中一个%运算符就把passport元组里的元素对应到了print函数的格式字符串空档中。这两个都是对元组拆包的应用。
2.1另外一个很优雅的写法当属不使用中间变量交换两个变量的值
a,b b,a2.2 还可以用*运算符把一个可迭代对象拆开作为函数的参数
divmod(20,8)
Out[12]: (2, 4)
t(20,8)
divmod(*t)
Out[14]: (2, 4)2.3 *args来获取不确定数量的参数
a, b, *rest range(5)
a, b, rest
Out[16]: (0, 1, [2, 3, 4])
a, b, *rest range(3)
a, b, rest
Out[18]: (0, 1, [2])
a, b, *rest range(2)
a, b, rest
Out[20]: (0, 1, [])
a, *body, c, d range(5)
a, body, c, d
Out[22]: (0, [1, 2], 3, 4)
*head, b, c, d range(5)
head, b, c, d
Out[24]: ([0, 1], 2, 3, 4)3、嵌套元组拆包
接受表达式的元组可以是嵌套式的例如(a, b, (c, d))。只要这个接受元组的嵌套结构符合表达式本身的嵌套结构Python就可以作出正确的对应。
4、具名元组
collections.namedtuple是一个工厂函数它可以用来构建一个带字段名的元组和一个有名字的类——这个带名字的类对调试程序有很大帮助。
Card collections.namedtuple(Card,[rank, suit])
card Card(28, heart)
card.rank
Out[30]: 28
card.suit
Out[31]: heart# 内部方法
card._fields
Out[32]: (rank, suit)
card._asdict()
Out[33]: {rank: 28, suit: heart}
card_data (27, heart)
card1 Card._make(card_data)
card1
Out[36]: Card(rank27, suitheart)5、作为不可变列表的元组
和列表相比除了跟增减元素相关的方法之外元组支持列表的其他所有方法。还有一个例外元组没有__reversed__方法但是这个方法只是个优化而已reversed(my_tuple)这个用法在没有__reversed__的情况下也是合法的。
5.1列表或元组的方法和属性那些有object支持的没有列出来
s [1,2,3,4]
s1 [a, b, c, d]
# s 和s1拼接
s.__add__(s1)
Out[40]: [1, 2, 3, 4, a, b, c, d]
# add的结果会更改s的值
s.__iadd__(s1)
Out[41]: [1, 2, 3, 4, a, b, c, d]
s
Out[42]: [1, 2, 3, 4, a, b, c, d]
# 在尾部添加一个元素
s.append(e)
s
Out[46]: [1, 2, 3, 4, a, b, c, d, e]
# 删除所有元素
s.clear()
s
Out[48]: []
# 列表中是否包含某个元素
s.__contains__(a)
Out[49]: False
# copy():对于List来说其第一层是实现了深拷贝但对于其内嵌套的List仍然是浅拷贝。因为嵌套的List保存的是地址复制过去的时候是把地址复制过去了嵌套的List在内存中指向的还是同一个。
a [1,[1,2,3],3]
b a.copy()
b[0] 3
b[1][0] 3
a
Out[59]: [1, [3, 2, 3], 3]
# a在s中出现的次数
s [a, b, c, a]
s.count(a)
Out[2]: 2#把下标2位置的内容删除
s.__delitem__(2)
s
Out[4]: [a, b, a]
# 在s中找到a第一次出现的位置
s.index(a)
Out[5]: 0
# 在位置1插入元素z
s.insert(1,z)
s
Out[7]: [a, z, b, a]
# 获取s的迭代器
s.__iter__()
Out[8]: list_iterator at 0x2d4d4a35550
iter(s)
Out[9]: list_iterator at 0x2d4d4a35130
# 获取s的元素数量
s.__len__()
Out[10]: 4
len(s)
Out[11]: 4# 2个s的拼接
s*2
Out[12]: [a, z, b, a, a, z, b, a]
s.__mul__(2)
Out[13]: [a, z, b, a, a, z, b, a]
# 删除最后位置的值并返回该值
s.pop()
Out[16]: a
s
Out[17]: [a, z, b]
# 删除1位置的值并返回该值
s.pop(1)
Out[18]: z
s
Out[19]: [a, b]
# 删除s中第一次出现的b
s [a, b, c,a, b]
s.remove(b)
s
Out[22]: [a, c, a, b]
# 将s的元素倒序排序
s.reverse()
s
Out[25]: [b, a, c, a]
# 返回s的倒序迭代器
reversed(s)
Out[26]: list_reverseiterator at 0x2d4d37589a0
s.__reversed__()
Out[27]: list_reverseiterator at 0x2d4d3758820
# 将s中位置为1的元素设置为f替换现有元素
s.__setitem__(1, f)
s
Out[29]: [b, f, c, a]
# 对s中的元素进行排序
s.sort()
s
Out[31]: [a, b, c, f]五、切片
1、在Python里像列表list、元组tuple和字符串str这类序列类型都支持切片操作。
1.1 为什么切片和区间会忽略最后一个元素
在切片和区间操作里不包含区间范围的最后一个元素是Python的风格这个习惯符合Python、C和其他语言里以0作为起始下标的传统。这样做带来的好处如下。 - 当只有最后一个位置信息时我们也可以快速看出切片和区间里有几个元素range(3)和my_list[:3]都返回3个元素。 - 当起止位置信息都可见时我们可以快速计算出切片和区间的长度用后一个数减去第一个下标stop-start即可。 - 这样做也让我们可以利用任意一个下标来把序列分割成不重叠的两部分只要写成my_list[:x]和my_list[x:]就可以了
l [1, 2, 3, 4, 5, 6]
l[:2]
Out[33]: [1, 2]
l[2:]
Out[34]: [3, 4, 5, 6]2、反向切片及间隔切片
s[::3]
Out[36]: bye
s[::-1]
Out[37]: elcycib
s[::-2]
Out[38]: eccb3、slice对象切片
price slice(6,10)
l banana10
l[price]
Out[41]: 104、给切片赋值
如果把切片放在赋值语句的左边或把它作为del操作的对象我们就可以对序列进行嫁接、切除或就地修改操作。
l list(range(10))
l
Out[43]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l[2:5] [20, 30]
l
Out[45]: [0, 1, 20, 30, 5, 6, 7, 8, 9]
del l[5:7]
l
Out[47]: [0, 1, 20, 30, 5, 8, 9]
# 如果赋值的对象是一个切片那么赋值语句的右侧必须是个可迭代对象。即便只有单独一个值也要把它转换成可迭代的序列
l[2:5] [100]
l
Out[49]: [0, 1, 100, 8, 9]
l[1:4] 100
TypeError: can only assign an iterable5、序列的加和乘
l [1,2,3]
l*5
Out[52]: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
2*abcd
Out[53]: abcdabcd
l [a, b]
Out[55]: [1, 2, 3, a, b]和*都遵循这个规律不修改原有的操作对象而是构建一个全新的序列。 如果在a * n这个语句中序列a里的元素是对其他可变对象的引用的话你就需要格外注意了因为这个式子的结果可能会出乎意料。比如你想用my_list[[]] * 3来初始化一个由列表组成的列表但是你得到的列表里包含的3个元素其实是3个引用而且这3个引用指向的都是同一个列表。这可能不是你想要的效果
6、序列的增量赋值
增量赋值运算符和*的表现取决于它们的第一个操作对象。简单起见我们把讨论集中在增量加法上但是这些概念对*和其他增量运算符来说都是一样的。背后的特殊方法是__iadd__ 用于“就地加法”。 例ab 如果a实现了__iadd__方法就会调用这个方法。同时对可变序列例如list、bytearray和array.array来说a会就地改动就像调用了a.extend(b)一样。但是如果a没有实现__iadd__的话ab这个表达式的效果就变得跟aab一样了首先计算ab得到一个新的对象然后赋值给a。也就是说在这个表达式中变量名会不会被关联到新的对象完全取决于这个类型有没有实现__iadd__这个方法。 总体来讲可变序列一般都实现了__iadd__方法因此是就地加法。而不可变序列根本就不支持这个操作对这个方法的实现也就无从谈起。
# 可变序列
l [1, 2, 3]
id(l)
Out[57]: 3113136609344
l *2
l
Out[59]: [1, 2, 3, 1, 2, 3]
id(l)
Out[60]: 3113136609344
# 不可变序列
t (1,2,3)
id(t)
Out[65]: 3113136658752
t*2
t
Out[67]: (1, 2, 3, 1, 2, 3)
id(t)
Out[68]: 31131238076806.1 关于的谜题
t (1, 2, [20, 30])
t[2] [50, 60]到底会发生下面4种情况中的哪一种
a. t变成(1, 2, [30, 40, 50, 60])。b.因为tuple不支持对它的元素赋值所以会抛出TypeError异常。c.以上两个都不是。d. a和b都是对的。 我刚看到这个问题的时候异常确定地选择了b但其实答案是d也就是说a和b都是对的示例2-15是运行这段代码得到的结果用的Python版本是3.4但是在2.7中结果也一样。
t (1, 2, [20, 30])
t[2] [50, 60]
TypeError: tuple object does not support item assignment
t
Out[72]: (1, 2, [20, 30, 50, 60])
# 避免抛错的写法
t[2].extend([60,70])
t
Out[74]: (1, 2, [20, 30, 50, 60, 60, 70])1. 不要把可变对象放在元组里面。2.增量赋值不是一个原子操作。我们刚才也看到了它虽然抛出了异常但还是完成了操作。3.查看Python的字节码并不难而且它对我们了解代码背后的运行机制很有帮助
7、list.sort方法和内置函数sorted
list.sort方法会就地排序列表也就是说不会把原列表复制一份。这也是这个方法的返回值是None的原因提醒你本方法不会新建一个列表。在这种情况下返回None其实是Python的一个惯例如果一个函数或者方法对对象进行的是就地改动那它就应该返回None好让调用者知道传入的参数发生了变动而且并未产生新的对象。例如random.shuffle函数也遵守了这个惯例。 与list.sort相反的是内置函数sorted它会新建一个列表作为返回值。不管是list.sort方法还是sorted函数都有两个可选的关键字参数。
如果被设定为True被排序的序列里的元素会以降序输出也就是说把最大值当作最小值来排序。这个参数的默认值是False。一个只有一个参数的函数这个函数会被用在序列里的每一个元素上所产生的结果将是排序算法依赖的对比关键字。比如说在对一些字符串排序时可以用keystr.lower来实现忽略大小写的排序或者是用keylen进行基于字符串长度的排序。这个参数的默认值是恒等函数identity function也就是默认用元素自己的值来排序。
fruits [grep, raspberry, apple, banana]
sorted(fruits)
Out[76]: [apple, banana, grep, raspberry]
fruits
Out[77]: [grep, raspberry, apple, banana]
sorted(fruits, reverseTrue)
Out[78]: [raspberry, grep, banana, apple]8、 其他序列类型
虽然列表既灵活又简单但面对各类需求时我们可能会有更好的选择。比如要存放1000万个浮点数的话数组array的效率要高得多因为数组在背后存的并不是float对象而是数字的机器翻译也就是字节表述。再比如说如果需要频繁对序列做先进先出的操作deque双端队列的速度应该会更快。
8.1 数组
如果我们需要一个只包含数字的列表那么array.array比list更高效。数组支持所有跟可变序列有关的操作包括.pop、.insert和.extend。另外数组还提供从文件读取和存入文件的更快的方法如.frombytes和.tofile。
8.2 内存视图
memoryview是一个内置类它能让用户在不复制内容的情况下操作同一个数组的不同切片
8.3 双向队列及其他形式的队列
利用.append和.pop方法我们可以把列表当作栈或者队列来用比如把.append和.pop(0)合起来用就能模拟队列的“先进先出”的特点。但是删除列表的第一个元素抑或是在第一个元素之前添加一个元素之类的操作是很耗时的因为这些操作会牵扯到移动列表里的所有元素。
collections.deque类双向队列是一个线程安全、可以快速从两端添加或者删除元素的数据类型。而且如果想要有一种数据类型来存放“最近用到的几个元素”deque也是一个很好的选择。这是因为在新建一个双向队列的时候你可以指定这个队列的大小如果这个队列满员了还可以从反向端删除过期的元素然后在尾端添加新的元素。
from collections import deque
dq deque(range(10), maxlen10)
dq
Out[81]: deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
dq.rotate(3)
dq
Out[83]: deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6])
dq.rotate(-4)
dq
Out[85]: deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
dq.appendleft(-1)
dq
Out[87]: deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])
dq.extend([11, 22, 33])
dq
Out[89]: deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33])
dq.extendleft([10, 20, 30, 40])
dq
Out[91]: deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8])除了deque之外还有些其他的Python标准库也有对队列的实现。queue提供了同步线程安全类Queue、LifoQueue和PriorityQueue不同的线程可以利用这些数据类型来交换信息。
multiprocessing这个包实现了自己的Queue它跟queue.Queue类似是设计给进程间通信用的。同时还有一个专门的multiprocessing.JoinableQueue类型可以让任务管理变得更方便。asyncioPython 3.4新提供的包里面有Queue、LifoQueue、PriorityQueue和JoinableQueue这些类受到queue和multiprocessing模块的影响但是为异步编程里的任务管理提供了专门的便利。heapq跟上面三个模块不同的是heapq没有队列类而是提供了heappush和heappop方法让用户可以把可变序列当作堆队列或者优先队列来使用。
参考《流畅的python》