本文是《流畅的Python》一书第二章的笔记。
Python内置了强大的数据结构,除了基本的数值类型和布尔值外,Python还有各种集合类型,包含了:序列(sequence)、映射(mapping)和集合(set)。
序列类型可分为两大类:
list
、tuple
、collections.deque
等这些能存放不同类型的数据。str
、bytes
、bytearray
、memoryview
、array.array
等只能存放一种数据类型。按照能否被修改还可以分为可变或不可变类型。
list
、collections.deque
、bytearray
、memoryview
、array.array
等。str
、bytes
和tuple
。可变与不可变
但是str
不是可变类型么?stra = strb + 'hello'
这样的表达式不是很常用么?
其实并不是这样的,当你执行上面得表达式的时候,python会为重新创建新的对象,并将stra
指向该对象。
stra = 'hello'
print (id(stra))
stra += 'world'
print (id(stra))
132518560
132503096
可以看到stra
已经不是原来的那个stra
了。下边再来看看可变类型。
a = ['hello']
print(id(a))
a += ['world']
print (id(a))
a = a+['test']
print (id(a))
132840184
132840184
132953232
可以看到当执行+=
操作时,可变类型list并未没有生成新的对象。但到了下边执行赋值操作时,还是重新生成了新的对象。
+= 和 = 赋值操作的区别
对于可变对象而言,+=操作并不会改变改变原对象,只是会就地操作。而对于不可变对象,Python会建立新的对象,并将其与当前变量关联。而=赋值操作则都会建立新的对象。
列表推导可以方便的生成我们需要的列表格式。
# 生成从0到10的x的平方的列表
a = [x*x for x in range(10)]
print (a)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
甚至还可以用于多个for循环的情况。
colors = ['black', 'white']
sizes = ['s', 'm', 'l']
tshirts = [(color, size) for size in sizes
for color in colors]
print(tshirts)
[('black', 's'), ('white', 's'), ('black', 'm'), ('white', 'm'), ('black', 'l'), ('white', 'l')]
在列表推导中python会忽略换行。
生成器在形式上类似于列表推导,只是适用的范围更广,生成器还可以用来推导元组、数组等。当然,更大的差别是,生成器遵守了迭代器协议,可以逐个的产出元素,而不是像循环那样一次建立一个完整的迭代对象。要想写出生成器表达式,只需要将列表推倒的方括号换为圆括号就好。
tuple_a = (x*x for x in range(10))
print(type(tuple_a))
print(tuple_a)
next(tuple_a)
<class 'generator'>
object <genexpr> at 0x07F0D900>
0
另一种写出生成器的方法是利用yield
关键字。一旦一个函数含有yield
关键字,这个函数就变成了一个生成器。
def generator_test():
for i in range(10):
yield i
print(type(generator_test()))
next(generator_test())
<class 'generator'>
0
sort()
方法用于就地排序一个列表,并返回None。注意只有列表类型可以调用这个方法。
a = [10,8,1,3,5,7]
a.sort()
print(a)
[1, 3, 5, 7, 8, 10]
注意这个排序是原地排序,也就是说并不会创建对象的副本。而且方法返回None,并不是排序后的数组。
sorted()
方法可以接受任意的可迭代对象作为参数,并返回排序后的列表。无论它接收什么可迭代的参数,都会返回列表。
a = [10,8,1,5,3,7]
print(sorted(a))
b = tuple(a)
print(sorted(b))
[1, 3, 5, 7, 8, 10]
[1, 3, 5, 7, 8, 10]
这两个函数都有两个可选参数。reverse
:设定为True,则按照降序排列。key
:作为排序的依据,一个只有一个参数的函数。比如将其设定为key=len则按照字符串长度排序。
a = ['Hell', 'World', 'zzz', 'aaaaaaa']
print (sorted(a, reverse=True, key=len))
['aaaaaaa', 'World', 'Hell', 'zzz']
bisect模块主要包含两个函数,bisect和insert。两个函数都是利用二分查找算法在有序序列中查找或插入元素。
bisect.bisect(haystack, needle)
在干草垛(haystack)中找针(needle)的位置,该位置保证把needle的值插入后序列仍为升序,并返回该位置的值。
import bisect
haystack = [1, 7, 9, 20, 25, 30, 32, 33]
position1 = bisect.bisect(haystack, 12)
position2 = bisect.bisect(haystack, 20)
print(position1, position2)
3 4
在值相同的情况下,bisect将20插入到了原值的右边,也可以利用bisect_left函数插入到原值左边。
haystack = [1, 7, 9, 20, 25, 30, 32, 33]
position = bisect.bisect_left(haystack, 20)
print(position)
3
bisect.insort(seq, item)
把变量item插入到序列seq中,并且仍然保持原序列升序。
haystack = [1, 7, 9, 20, 25, 30, 32, 33]
bisect.insort(haystack, 10)
print (haystack)
[1, 7, 9, 10, 20, 25, 30, 32, 33]
这个方法类似于sort函数的就地排序,它将item插入到原序列后返回None。同样的,这个方法也可以利用insort_left将值插入到原序列相同值的左边。
当需要一个只包含大量数字的序列时,可以使用数组,底层的C语言实现使得数组比列表更加高效。
array.array(typecode, seq),typecode指定转化为array的类型,一旦指定array类型就不可变。
typecode | C类型 | Python类型 |
---|---|---|
‘b’ | signed char | int |
‘B’ | unsigned char | int |
‘u’ | - | unicode |
‘i’ | signed char | int |
‘I’ | unsigned char | int |
‘f’ | float | float |
‘d’ | double | double |
import array
tup = (1,2,3,4,5)
arr = array.array('f', tup)
print(arr)
array('f', [1.0, 2.0, 3.0, 4.0, 5.0])
collections.deque类是一个双向队列,可以从两端添加或者删除元素。
import collections
dq = collections.deque(range(10), maxlen=10) # 需要指定队列大小,且一旦指定,队列大小不可变
print (dq)
dq.appendleft(-1) #从左边继续添加元素时,会把最右边的元素“挤掉”
print (dq)
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
deque([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8], maxlen=10)
类似于列表,deque也可以进行pop、append、remove、clear等操作,不同的是deque对于appeed和pop这两种操作都提供了从左边操作的方法,即appendleft和popleft。