3.1 数据结构和序列
元组是一个固定长度,不可改变的python序列对象。创建元组的方法就是用逗号分隔一列值
tup = 4,5,6
print(tup)
(4, 5, 6)
当用复杂的表达式定义元组时,将值放到圆括号中
nested_tup = (4,5,6),(7,8)
print(nested_tup)
((4, 5, 6), (7, 8))
tuple可以将任意序列或迭代器转换成元组,同样可以用方括号访问元组中的元素
tuple([4,0,2])
(4, 0, 2)
tuple('string')
('s', 't', 'r', 'i', 'n', 'g')
tup[0]
's'
如果元组中的某个对象是可变的,比如列表,可以在原位进行修改。可以用加号运算符将元组串联起来,元组乘以一个整数,像列表一样,会将几个元组的复制串联起来。对象之间是引用的关系而不是复制
(4, None, 'foo') + (6, 0) + ('bar',)
(4, None, 'foo', 6, 0, 'bar')
('foo', 'bar') * 4
('foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'bar')
拆分元组
seq = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
for a, b, c in seq:
print('a={0}, b={1}, c={2}'.format(a, b, c))
a=1, b=2, c=3
a=4, b=5, c=6
a=7, b=8, c=9
tuple方法
count()可以统计某个值的出现频率
a = (1, 2, 2, 2, 3, 4, 2)
a.count(2)
4
列表长度可变,内容可以被修改。可以用方括号定义或用list函数
tup = ('foo', 'bar', 'baz')
list(tup)
['foo', 'bar', 'baz']
list 函数常用来在数据处理中实体化迭代器或生成器:
list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
添加和删除元素
可以用append在列表末尾添加元素
insert可以在特定位置插入元素,insert的逆运算是pop,它移除并返回指定位置的元素。remove去除某个值,其会先寻找第一个值并除去
用in可以检查列表是否包含某个值,否定in可以再加上一个not
print(b_list)
['foo', 'bar', 'baz']
b_list.insert(1,'red')
['foo', 'red', 'bar', 'baz']
b_list.pop(2)
['foo', 'red', 'baz']
'dwarf' in b_list
False
'dwarf' not in b_list
True
串联和组合列表
与元组类似,可以用加号将两个列表串联起来
如果已经定义一个列表,用extend方法可以追加多个元素
[4, None, 'foo'] + [7, 8, (2, 3)]
[4, None, 'foo', 7, 8, (2, 3)]
x = [4, None, 'foo']
x.extend([7, 8, (2, 3)])
print(x)
[4, None, 'foo', 7, 8, (2, 3)]
sort函数可以将一个列表原地排序
切片
切片的基本形式是在方括号中使用start:stop,负数表明从后往前切片。在第二个冒号后面使用step,可以隔一个取一个元素。使用-1可以将列表或元组颠倒过来
seq = [7, 2, 3, 7, 5, 6, 0, 1]
seq[1:5]
[2, 3, 7, 5]
seq[-4:]
[5, 6, 0, 1]
seq[::2]
[7, 3, 5, 0]
seq[::-1]
[1, 0, 6, 5, 7, 3, 2, 7]
序列函数
enumerate函数:在索引数据时,使用enumerate计算序列dict映射到位置的值
some_list = ['foo', 'bar', 'baz']
mapping = {}
for i, v in enumerate(some_list):
mapping[v] = i
print(mapping)
{'foo': 0, 'bar': 1, 'baz': 2}
sorted函数可以从任意序列的元素返回一个新的排好序的列表
sorted([7, 1, 2, 6, 0, 3, 2])
[0, 1, 2, 2, 3, 6, 7]
zip函数可以将多个列表,元组或其它序列成对组合成一个元组列表
seq1 = ['foo', 'bar', 'baz']
seq2 = ['one', 'two', 'three']
zipped = zip(seq1, seq2)
list(zipped)
[('foo', 'one'), ('bar', 'two'), ('baz', 'three')]
zip可以处理任意多的序列,元素个数取决于最短的序列;同时迭代多个序列可结合enumerate使用
seq3 = [False, True]
list(zip(seq1, seq2, seq3))
[('foo', 'one', False), ('bar', 'two', True)]
for i, (a, b) in enumerate(zip(seq1, seq2)):
print('{0}: {1}, {2}'.format(i, a, b))
0: foo, one
1: bar, two
2: baz, three
reversed函数可以从后向前迭代一个序列,其是一个生成器,只有实例化之后才能创建翻转的序列
list(reversed(range(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
字典是键值对的大小可变的集合,键和值都是python对象。创建字典的方法之一是使用尖括号,用冒号分隔键和值
empty_dict = {}
d1 = {'a' : 'some value', 'b' : [1, 2, 3, 4]}
print(d1)
{'a': 'some value', 'b': [1, 2, 3, 4]}
可以像访问列表或元组中的元素一样,访问,插入或设定字典中的元素
d1[7] = 'an integer'
print(d1)
{'a': 'some value', 'b': [1, 2, 3, 4], 7: 'an integer'}
可以用检查列表和元组是否包含某个值的方法,检查字典中是否包含某个键
'b' in d1
True
可以用 del 关键字或 pop 方法(返回值的同时删除键)删除值,用 update 方法可以将一个字典与另一个融合,updata方法是原地改变字典,因此任何传递给updata的键的旧的值都会被舍弃
d1.update({'b' : 'foo', 'c' : 12})
print(d1)
{'a': 'some value', 'b': 'foo', 7: 'an integer', 'c': 12}
序列创建字典快速方式:
mapping = dict(zip(range(5), reversed(range(5))))
print(mapping)
{0: 4, 1: 3, 2: 2, 3: 1, 4: 0}
集合是无序的不可重复的元素的集合,合并是取两个集合中不重复的元素,可以用union方法或| 运算符。交集的元素包含在两个集合中,可以用 intersection 或 & 运算符。
set([2, 2, 2, 1, 3, 3])
{1, 2, 3}
a = {1, 2, 3, 4, 5}
b = {3, 4, 5, 6, 7, 8}
a.union(b)
{1, 2, 3, 4, 5, 6, 7, 8}
a.intersection(b)
{3, 4, 5}
列表推导式它允许用户方便的从一个集合过
滤元素,形成列表,在传递参数的过程中还可以修改元素
[expr for val in collection if condition]
等价于
result = []
for val in collection:
if condition:
result.append(expr)
举例:
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
[x.upper() for x in strings if len(x) > 2]
['BAT', 'CAR', 'DOVE', 'PYTHON']
lambda函数也叫做匿名函数,即函数没有具体的名称。lambda和普通函数相比,省去了函数名称,所以在使用python写脚本的时候,使用lambda可以省去定义函数的过程。lambda语句中,冒号前是参数,后是返回值。以下两个语句含义一样。
def short_function(x):
return x * 2
equiv_anon = lambda x: x * 2
生成器和迭代器的关系
生成器是构造新的可迭代对象的一种简单方式。一般的函数执行之后只会返回单个值,而生成器则是以延迟的方式返回一个值序列,即每返回一个值之后暂停,直到下一个值被请求时再继续。要创建一个生成器只需将函数中的return 替换为yield即可
def squares(n=10):
print('Generating squares from 1 to {0}'.format(n ** 2))
for i in range(1, n + 1):
yield i ** 2
调用该生成器时,没有任何代码会被立即执行。
print(squares())
直到从该生成器中请求元素时,才会开始执行代码
for x in gen:
print(x,end='')
Generating squares from 1 to 100
149162536496481100
生成器表达式这是一种类似于列表,字典,集合推导式的生成器。其创建方式为,把列表推导式两端的方括号改成圆括号
gen = (x ** 2 for x in range(100))
print(gen)
at 0x000001D78D458DB0>
等价式:
def _make_gen():
for x in range(100):
yield x ** 2
gen = _make_gen()
生成器表达式也可以取代列表推导式,作为函数参数
sum(x ** 2 for x in range(100))
328350
迭代器
迭代是说一件事重复做很多次,最经典是就是for循环。for循环可以对一切有iter方法的对象进行迭代。那么一个对象是否可迭代完全取决于该对象是否有iter方法,调用对象的iter方法,就会返回一个迭代器,这个迭代器一定具有next方法,在调用这个迭代器的next方法时,迭代器就回返回它的下一个值。所以迭代器有一个很重要的特性:不可逆,只能前进不能后退。
for循环就是这样工作的,for循环在循环一个对象的时候,会调用这个对象的iter方法,得到一个迭代器,然后再调用这个迭代器的next方法去获得这个迭代器中包含的每个值。