1.数据结构和序列
1.1 元组
元组
是一种固定长度、不可变的Python对象序列。
tuple = 1, 2, 3
tup
(1, 2, 3)
生成元素是元组的元组:
nested_tup = (1, 2, 3), (4, 5,6)
nested_tup
((1, 2, 3), (4, 5,6))
任意序列 / 迭代器 ➡ 元组:
tuple([6, 0, 7])
(6, 0, 7)
tup = tuple('python')
tup
('p', 'y', 't', 'h', 'o', 'n')
通过[ ]获取元组的元素:
tup[0]
'p'
对象元组中存储的对象本身其本身是可变的,但是元组一旦被创建,各个位置上的对象是无法被修改的:
//非法操作,会报错
tup = tuple(['exp', [0, 1], True])
tup[2] = False
若元组中的某个对象是可变的,比如列表,则该对象可进行修改:
tup = tuple(['exp', [0, 1], True])
tup[1].append(2)
tup
('exp', [0, 1, 2], True)
使用+
号连接元组:
('python', None, 607) + (0, 1) + ('game')
('python', None, 607, 0, 1, 'game')
使用*
号生成含有多份拷贝的元组:
('python', 'game') * 3
('python', 'game', 'python', 'game', 'python', 'game')
1.1.1 元组拆包
tup = (1, 2, 3)
a, b, c = tup
a
b
c
1
2
3
嵌套元组拆包:
tup = 1, 2, 3, (6, 0, 7)
a, b, c, (x, y, z) = tup
z
7
拆包以遍历元组或列表组成的序列:
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
高级元组拆包:
values = 1, 2, 3, 4, 5
a, b, *rest = values
a, b
(1, 2)
rest
[3, 4, 5]
编程时大多使用下划线(_)来表示不想要的变量:a, b, *_ = values
1.1.2 元组方法
a = (0, 1, 1, 1, 1, 0, 1)
a.count(1)
5
1.2 列表
列表
是长度可变、内容可变的序列,可以用[]
或者list
类型函数来定义列表。
list_1 = [1, 2, 3, None]
list_1
[1, 2, 3, None]
tup = ('a', 'b', 'c')
list_2 = list(tup)
list_2
['a', 'b', 'c']
list_2[2] = 'x'
list_2
['a', 'b', 'x']
迭代器 / 生成器 ➡ 列表:
gen = range(10)
gen
range(0, 10)
list(gen)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1.2.1 增加和移除元素
append()函数
:将元素添加到列表的尾部
list_ap = ['a', 'b', 'c']
list_ap.append('x')
list_ap
['a', 'b', 'c', 'x']
insert()函数
:将元素插入到指定的列表位置
list_in = ['a', 'b', 'c']
list_in.insert(1, 'x')
list_in
['a', 'x', 'b', 'c']
pop()函数
:将特定位置的元素移除并返回
list_p = ['a', 'x', 'b', 'c']
list_p.pop(1)
'x'
list_p
['a', 'b', 'c']
remove()函数
:定位第一个符合要求的值并移除它
list_re = ['a', 'b', 'c', 'a']
list_re.remove('a')
list_re
['b', 'c', 'a']
in关键字
可用于检查一个值是否在列表中:
list_in = ['a', 'b', 'c']
'a' in list_in
True
not in关键字
可用于检查一个值是否不在列表中:
list_not = ['a', 'b', 'c']
'a' not in list_not
False
1.2.2 连接和联合列表
两个列表可以用+
号连接:
[6, None, 'peer'] + [0, 1, (1, 0)]
[6, None, 'peer', 0, 1, (1, 0)]
extend()函数
:向列表中添加多个元素
x = [6, 0, 7, None, 'peer']
x.extend([0, 1, (1, 0)])
x
[6, 0, 7, None, 'peer', 0, 1, (1, 0)]
如果使用append()函数,则插入的是[0, 1, (1, 0)]这一个元素。
1.2.3 排序
sort()函数
:对列表内部进行排序(无须新建一个对象)
a = [6, 0, 7]
a.sort()
a
[0, 6, 7]
通过字符串的长度进行排序:
b = ['saw', 'small', 'He', 'foxes', 'six']
b.sort(key=len)
b
['He', 'saw', 'six', 'small', 'foxes']
1.2.4 二分搜索和已排序列表的维护
bisect()函数
:返回指定元素应当被插入的位置
import bisect
// 索引
// 0 1 2 3 4 5 6
c = [1, 2, 2, 2, 3, 4, 7]
bisect.bisect(c, 2)
4
bisect.bisect(c, 5)
6
insort()函数
:将指定元素插入到相应位置
bisect.insort(c, 6)
c
[1, 2, 2, 2, 3, 4, 6, 7]
1.2.5 切片
基本形式:start: stop
使用切片符号对大多数序列类型选取其子集
seq = [1, 2, 3, 4, 5, 6, 7]
seq[1:5]
[2, 3, 4, 5]
切片还可以将序列赋值给变量:
seq[3: 4] = [8, 9]
seq
[1, 2, 3, 8, 9, 5, 6, 7]
注: 包含起始位置start的索引,但是不包含结束位置stop的索引,元素数量的stop-start。
省略start
和stop
:
seq = [1, 2, 3, 4, 5, 6, 7]
seq[: 5]
[1, 2, 3, 4, 5]
seq = [1, 2, 3, 4, 5, 6, 7]
seq[3:]
[4, 5, 6, 7]
负索引可以从序列的尾部进行索引:
seq = [1, 2, 3, 4, 5, 6, 7]
seq[-4:]
[4, 5, 6, 7]
seq = [1, 2, 3, 4, 5, 6, 7]
seq[-6: -2]
[2, 3, 4, 5]
步进值step
:每个多少个数取一个值
seq = [1, 2, 3, 4, 5, 6, 7]
seq[: : 2]
[1, 3, 5, 7]
元素翻转,可以设置step
为-1
seq = [1, 2, 3, 4, 5, 6, 7]
seq[: : -1]
[7, 6, 5, 4, 3, 2, 1]
1.3 内建序列函数
1.3.1 enumerate
enumerate()函数
:返回(i, value)
即(元素的值,元素的索引)
的序列
// 构造一个字典
list_a = ['peer', 'apple', 'banana']
// 空字典
mapping = {}
for i, value in enumerate(list_a):
mapping[v] = i
mapping
{'peer': 0, 'apple': 1, 'banana': 2}
1.3.2 sorted
sorted()函数
:返回一个根据任意序列中的元素新建的已排序列表
sorted([7, 1, 2, 6, 0, 3, 2])
[0, 1, 2, 2, 3, 6, 7]
sorted('horse race')
[' ', 'a', 'c', 'e', 'e', 'h' ,'o', 'r', 'r', 's']
1.3.3 zip
zip()函数
:将列表、元组或者其他序列的元素配对,新建一个元组构成的列表。
seq_1 = ['a', 'b', 'c']
seq_2 = ['one', 'two', 'three']
zipped = zip(seq_1, zeq_2)
list(zipped)
[('a', 'one'), ('b', 'two'), ('c', 'three')]
zip()
可以处理任意长度的序列,生成列表的长度由最短的序列
决定:
seq_1 = ['a', 'b', 'c']
seq_2 = ['one', 'two', 'three']
seq_3 = [False, True]
zipped = zip(seq_1, zeq_2,seq_3)
list(zipped)
[('a', 'one', False), ('b', 'two', True)]
zip()
同时遍历多个序列:
seq_1 = ['a', 'b', 'c']
seq_2 = ['one', 'two', 'three']
for i, (a, b) in enumerate(zip(seq_1,seq_2)):
print('{0}: {1}, {2}'.format(i, a, b))
0: a, one
1: b, two
2: c, three
zip()
将行的列表转化为列的列表:
names = [('Lebron', 'James'), ('Allen', 'Iverson'), ('Stephen', 'Curry')]
first_names, last_names = zip(*names)
first_name
('Lebron', 'Allen', 'Stephen')
last_name
('James', 'Iverson', 'Curry')
1.3.4 reversed
reversed()函数
:将序列的元素倒序排列。
list(reversed(range(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
注:reversed是一个生成器。
1.4 字典
字典dict
又名哈希表
或者关联数组
,拥有灵活尺寸的键值对
集合。
empt_dict = {}
dict_1 = {'a': 'apple', 'b': [0, 1]}
dict_1
{'a': 'apple', 'b': [0, 1]}
插入元素到字典中:
dict_1[44] = 'peer'
dict_1
{'a': 'apple', 'b': [0, 1], 44: 'peer'}
访问字典中的元素
dict_1['b']
[0, 1]
in关键字
检查字典中是否含有一个键:
'b' in dict_1
True
del关键字
可用于删除值:
dict_1 = {'a': 'apple', 'b': [0, 1], 44: 'peer'}
dict_1[33] = 'cola'
dict_1['extra_index'] = 'juice'
dict_1
{'a': 'apple',
'b': [0, 1],
44: 'peer',
33: 'cola',
'extra_index': 'juice'}
del dict_1[33]
dict_1
{'a': 'apple',
'b': [0, 1],
44: 'peer',
'extra_index': 'juice'}
pop()函数
:删除值的同时,返回被删除的值
ret = dict_1.pop('extra_index')
ret
'juice'
dict_1
{'a': 'apple',
'b': [0, 1],
44: 'peer'}
keys()函数
:提供字典的键的迭代器
dict_1 = {'a': 'apple', 'b': [0, 1], 44: 'peer'}
list(dict_1.keys())
['a', 'b', 44]
values()函数
:提供字典的键的迭代器
dict_1 = {'a': 'apple', 'b': [0, 1], 44: 'peer'}
list(dict_1.values())
['apple', [0, 1], 'peer']
update()
:合并两个字典
dict_1 = {'a': 'apple', 'b': [0, 1], 44: 'peer'}
dict_2 = {'b': [33, 44], 'c': 'cola'}
dict_1.update(dict_2)
dict_1
{'a': 'apple', 'b': [33, 44], 44: 'peer', 'c': 'cola'}
注:若传给update()函数的字典含有同样的键,则原本字典对应的键的值将会被覆盖。
1.4.1 从序列生成字典
mapping = dict((zip(range(5), reversed(range(5)))))
mapping
{0: 4, 1: 3, 2: 2, 3: 1, 4: 0}
1.4.2 默认值
将字词组成的列表
根据首字母
分类为包含列表的字典
:
// 由字词组成的列表
words = ['apple', 'bat', 'bar', 'atom', 'book']
// 空字典
by_letter = {}
// 遍历
for word in words:
letter = word[0]
if letter not in by_letter:
by_letter[letter] = [word]
else:
by_letter[letter].append(word)
by_letter
{'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}
可以用setdefault()
简化为:
for word in words:
letter = word[0]
by_letter.setdefault(letter, []).append(word)
还可以用defaultdict类
实现:
from collections import defaultdict
by_letter = defaultdict(list)
for word in words:
by_letter[word[0]].append(word)
1.4.3 有效的字典键类型
键
必须是不可变的对象。hash()函数
:检查一个对象是否可以哈希化(即是否可以用作字典的键)。
hash('string')
5023931463650008331
// 非法操作
// 元组内的元素[2, 3]是列表,是可变的
hash((1, 2, [2, 3]))
将列表转化为元组,然后作为键:
dict_2 = {}
dict_2[tuple([1, 2, 3])] = 5
dict_2
{(1, 2, 3): 5}
1.5 集合
集合
是一种无序的、元素唯一、元素不可变的容器。
两种创建方式:通过set()函数
或者用字面值集与大括号的语法。
// 方式一
set([2, 2, 2, 1, 3, 3])
{1, 2, 3}
// 方式二
{2, 2, 2, 1, 3, 3}
{1, 2, 3}
集合操作:并集
a = {1, 2, 3, 4, 5}
b = {3, 4, 5, 6, 7, 8}
// 等效于 a | b
a.union(b)
{1, 2, 3, 4, 5, 6, 7, 8}
集合操作:交集
// 等效于 a & b
a.intersection(b)
{3, 4, 5}
集合操作:将a的内容设置为a与b的并集
// 等效于 a |= b
a.update(b)
a
{1, 2, 3, 4, 5, 6, 7, 8}
集合的元素必须是不可变的:
my_data = [0, 1]
my_set = {tuple(my_data)}
my_set
{(0, 1)}
集合操作:检查一个集合是否是另一个集合的子集(包含于)或超集(包含)
set_a = {1, 2, 3, 4, 5}
{1, 2, 3}.issubset(set_a)
True
set_a.issuperset({1, 2, 3})
True
集合操作:判等
{1, 2, 3} == {3, 2, 1}
True
1.6 列表、集合、字典的推导式
列表的推导式:
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
[x.upper() for x in strings if len(x) > 2]
['BAT', 'CAR', 'DOVE', 'PYTHON']
集合的推导式:
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
unique_lengths = {len(x) for x in strings}
unique_lengths
{1, 2, 3, 4, 6}
// 使用map()函数
set(map(len, strings))
{1, 2, 3, 4, 6}
字典的推导式:
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
loc_mapping = {val: index for index, val in enumerate(strings)}
loc_mapping
{'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5}
1.6.1 嵌套列表推导式
找出列表中包含的所有含有2个以上字母e的名字:
all_ data = [['John', 'Emily', 'Michael', 'Mary', 'Steven'],
['Maria', 'Juan', 'Javier', 'Natalia', 'Pilar']]
result = [name for names in all_data for name in names
if name.count('e') >= 2]
result
['Steven']
将含有整数元组的列表扁平化为一个一维整数列表:
tuples_33 = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
flattened = [x for tup in tuples_33 for x in tup]
flattened
[1, 2, 3, 4, 5, 6, 7, 8, 9]
列表嵌套:
[[x for x in tup] for tup in tuples_33]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2. 函数
函数参数:关键字参数必须跟在位置参数后。
// 正则表达式模块re
import re
// 移除标点符号
def remove_punctuation(value):
return re.sub('[!#?]', '', value)
// 去除空格、移除标点符号、适当调整大小写
clean_ops = [str.strip, remove_punctuation, str.title]
// 清洗字符串列表
def clean_strings(strings, ops):
result = []
for value in strings:
for function in ops:
value = function(value)
result.append(value)
return result
states = [' Tom ', 'Google!', 'Google', 'google', 'CuRRy', 'lebron james##', 'Allen iverson?']
clean_strings(states, clean_ops)
['Tom',
'Google',
'Google',
'Google',
'Curry',
'Lebron James',
'Allen Iverson']
将函数作为一个参数传给其他的函数:
for x in map(remove_punctuation, states):
print(x)
Tom
Google
Google
Google
Curry
Lebron James
Allen Iverson
2.1 匿名Lambda函数
lambda关键字
:用于声明一个匿名函数。
strings = ['foo', 'card', 'bar', 'aaaa', 'abab']
strings.sort(key=lambda x: len(set(list(x))))
['aaaa', 'foo', 'abab', 'bar', 'card']
2.2 生成器
遍历字典,获得字典的键:
dict_it = {'a': 1, 'b': 2, 'c': 3}
for key in dict_it:
print(key)
'a'
'b'
'c'
迭代器
:一种用于在上下文中向Python解释器生成对象的对象。
dict_it = {'a': 1, 'b': 2, 'c': 3}
dict_iterator = iter(dict_it)
list(dict_iterator)
['a', 'b', 'c']
创建一个生成器,仅需在函数中将return关键字
改为yield关键字
。
def squares(n=10):
print('Generating squares from 1 to {0}'.format(n ** 2))
for i in range(1, n + 1):
yield x ** 2
gen = squares()
for x in gen:
print(x, end=' ')
Generating squares from 1 to 100
1 4 9 16 25 36 49 64 81 100
2.2.1 生成器表达式
sum(x ** 2 for x in range(100))
328350
dict((i, i ** 2) for i in range(5))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
2.2.2 itertools模块
groupby()函数
:可以根据任意的序列和一个函数,通过函数的返回值对序列中连续的元素进行分组。
import itertools
first_letter = lambda x: x[0]
names = ['Alan', 'Adam', 'Wes', 'Will', 'Albert', 'Steven']
for letter, names in itertools.groupby(names, first_letter):
print(letter, list(names))
A ['Alan', 'Adam']
W ['Wes', 'Will']
A ['Albert']
S ['Steven']
3. 文件与操作系统
打开文件进行读取或写入(默认情况下是以只读模式'r'
打开的):
path = 'examples/exp.txt'
f = open(path)
with open(path) as f:
lines = [x.rstrip() for x in f]
使用with语句,文件会在with代码块结束后自动关闭。
模式 | 含义 |
r | 只读模式 |
w | 只写模式, 创建新文件(清除路径下的同名文件中的数据) |
x | 只写模式,创建新文件,但存在同名路径时会创建失败 |
a | 添加到已经存在的文件(若不存在则进行创建) |
r+ | 读写模式 |
b | 二进制文件的模式,添加到别的模式中(比如’rb’或者’wb’) |
t | 文件的文本模式(自动将字节解码为Unicode)。如果未指明模式,默认使用此模式,可以添加到别的模式中(比如’rt’或者’xt’) |
with open('temp.txt', 'w') as handle:
handle.writelines(x for x in open(path) if len(x) > 1)
with open('tmp.txt') as f:
lines = f.readlines()
lines