文章目录
1. 元组tuple
元组 :长度固定,元素不可变,赋值会报错
(如果元素是可变的,则可修改该元素)
nested_tup = (4,5,6),(7,8) # 嵌套元组
nested_tup # ((4, 5, 6), (7, 8))
tup = tuple('string') # 序列类型转换为元组
tup
tup[0] # 通过下标访问里面元素
tup = (1,2,3)+(4,5) # 加号连接元组为一个元组
tup = tup*4 # 乘号复制元组的值为一个元组
拆包: 多个值赋给多个值,python会自动识别
a, b, c = (4,5,6) # 多个值可以为一个元组中的多个元素
b
a, b, (c, d) = 4,5,(6,7)
d
# 通过拆包交换变量名
a, b = b, a
# 通过拆包遍历序列
seq = [(1,2,3),(4,5,6),(7,8,9)]
for a,b,c in seq: # 对每个元素进行拆包,相当于两重循环
print('a={},b={},c={}'.format(a,b,c))
# 通过拆包从函数返回多个值
# 高级拆包:*rest:不是一一对应关系了,在获得我们指定位置想要的元素之后,对于剩余的其他所有元素统统放入rest变量中,
# rest只是名字,可以是*任何名字,对于不想要的变量,可以用_表示
values = 1,2,3,4,5
a,*rest,b= values # a=1,b=5,rest=[2,3,4]
元组的方法:count:计数,某个值在元组中出现的次数
a = 1,1,2,2,2,3
a.count(2) # 3次
2.列表list
可修改,使用[]创建列表或list将别的序列或迭代器(例如range)转换为列表
l = [1,2,3] # []创建列表
l=[] # 创建空列表
tup = (4,5,6)
b = list(tup) # 将别的序列转换为列表
b[1] = 1 # 修改元素的值:直接赋值
b # [4,1,6]
1.向列表中添加元素
## 列表尾部追加元素:.append()
l.append('a')
## 在任意位置插入元素:.insert(位置,元素),代价较高
l.insert(1,'b')
2.移除列表中的元素
## 通过索引移除指定位置的元素:.pop(索引)
l.pop(2)
## 通过值直接移除元素,只移除第一个找到的元素:.remove()
l.remove('a')
3.检查列表是否包含某个元素:in,not in,返回True or False,原理是线性逐个扫描
'a' in l
'a' not in l
4.连接列表:
+:返回一个新列表,代价较高
.extend(list): 将新元素的列表添加到已存在的列表,相当于扩展,推荐
list_of_lists = [[1,2,3],['a','b']]
l = []
for chunk in list_of_lists: # 对于包含许多小列表的大列表
l.extend(chunk) # 依次连接这些小列表
l # [1, 2, 3, 'a', 'b']
5.排序:
.sort():列表自带的排序方法,将列表直接更新
l.sort()
l
# 参数key=函数名:函数生成排序值,根据这个排序
# 参数reverse=True/False,默认升序False
l = ['a','aaa','aa']
l.sort(key=len,reverse=True) # 按照元素长度降序排序
l # ['aaa', 'aa', 'a']
对于已排好序的列表,使用bisect模块,实现二分搜索和插值
import bisect
l=[1,2,3,4,7] # 已排序列表
bisect.bisect(l,5) # 在l中找出5应该被插入的位置
bisect.insort(l,5) # 向l中插入5
l # [1, 2, 3, 4, 5, 7]
3. 切片
对序列按索引取子集,区间是[start,end),不包含end,元素个数是end-start。
省略start或end则默认从开头或到结尾,包括开头和结尾。
可以使用负索引
可以带步长:seq[start: end: step],步长为-1时,将序列逆序。
l = [7,2,3,7,5,6,0,1]
l[1:5] # [2, 3, 7, 5]
l[3:5] = [6,3] # 将位置3,4的元素7,5替换为6,3
l[3:4] = [6,3] # 将位置3的元素6替换为6,3, l is [7, 2, 3, 6, 3, 3, 6, 0, 1]
l[3:] # 从位置3的元素到最后一个
l[-4:] # 从位置-4的元素到最后一个,搜索方向都是正向,只不过两套索引,[3, 6, 0, 1]
l[::2] # 每隔一个取一个值 [7, 3, 3, 6, 1]
l[::-1] # 列表倒序,[1, 0, 6, 3, 3, 6, 3, 2, 7]
4. 常用序列函数
enumerate()
遍历序列的同时带上索引
for i,value in enumerate(seq):
# do something using i or value
sorted()
对任意序列排序,返回新的列表,参数同key,reverse
s = 'apple'
s1 = sorted(s,reverse=True) # 对字符串的字符序列降序排列
s1 # ['p', 'p', 'l', 'e', 'a']
zip()
拉链,将多个序列按元素挨个配对,生成由配对元组构成的zip对象
序列长度不同时,最终长度由最短的序列决定
seq1 = [1,2,3]
seq2 = ['a','b','c']
zipped = zip(seq1,seq2)
list(zipped) # [(1, 'a'), (2, 'b'), (3, 'c')]
解开配对,使用value1,…=zip(*配对对象)
value1,value2 = zip(*zipped)
value2 # ('a', 'b', 'c')
常用场景:同时遍历多个序列
for i,(a,b) in enumerate(zip(seq1,seq2)): # zip配对后是配对元组
print('{0}:{1},{2}'.format(i,a,b))
reversed()
将序列元素倒序,是一个生成器,需要用list()或for循环对其实例化才能看见里面的内容。
list(reversed(range(10))) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
5. 字典
也叫哈希表或关联数组,是键值对集合,使用大括号{}创建字典,用逗号分隔键值对。
字典中没有位置索引,key就是索引
empty_d={} # 建立空字典
d = {'a':'some value','b':[1,2,3]} # 值可以是任何类型
d['c'] = 8 # 通过key插入新元素
d['c'] # 通过key访问元素
'b' in d # 检查某个键是否在字典中
- 删除元素,key与value是绑定的
.pop(key) :返回对应的值,并从字典中移除
del d[key] :直接删除
# .pop(key)返回对应的值,并从字典中移除
ret=d.pop('c') # d is {'a': 'some value', 'b': [1, 2, 3]}
# del d[key]:直接删除
d[1] = '1' # 增加一个元素1:'1' # 注意,加引号是字符串,这里的key是整数1
del d[1] # 字典中没有位置索引,key就是索引
- 输出键的列表,值的列表
# 可以用list()更清楚的表示格式
d.keys()
list(d.values())
- 合并两个字典,键相同的元素将被覆盖,相当于扩展
d1 = {'a':'some value','b':[1,2,3]}
d2 = {'b':'foo','c':8}
d1.update(d2)
d1 # {'a': 'some value', 'b': 'foo', 'c': 8}
- 由于字典本质是含有两个元素的元组(2-元组)的集合,因此2-元组的列表可以转换成字典。
# 配对后的序列变成字典
mapping = dict(zip(range(5),reversed(range(5))))
mapping # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}
- 默认值
常见场景:将字典的值聚集成另一种值集合
比如,将单词按照首字母归类,一类是一个列表
普通做法:
words = ['apple','bat','bar','atom','book']
d = {}
for word in words:
initial = word[0] # 取出首字母
if initial not in d: # 如果字典中没有该首字母,
d[initial] = [word] # 则新建一个元素,值是列表
else:
d[initial].append(word) # 如果有该首字母,则把该单词直接追加到值列表
d # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}
.setdefault(key, default=None)方法:Insert key with a value of default if key is not in the dictionary.
当key不存在时,插入一个带默认值的key,返回该key的值,当key存在时,返回该key对应的值。
# 若key不存在,添加该元素,使用默认值
d={'a':1}
d.setdefault('b',2) # 2,d is {'a': 1, 'b': 2}
# 若key已存在,则忽略默认值,返回该key的值
d={'a':1,'b':0}
d.setdefault('b',2) # 0, d is {'a': 1, 'b': 0}
d
所以上述任务的简单做法是:
words = ['apple','bat','bar','atom','book']
d = {}
for word in words:
initial = word[0] # 取出首字母
d.setdefault(initial,[]).append(word) # 设置默认值是空列表
更简单的做法是使用内建的集合模块collections中的defaultdict类:
from collections import defaultdict
d = defaultdict(list) # 生成一个字典,所有键的默认值都是空列表
for word in words:
d[word[0]].append(word) # 按照索引word[0]返回值,空列表或非空列表
defaultdict()方法:
普通的字典用法一般是dict={},添加元素dict[key] =value,调用的时候dict[key] = xxx,但前提是key在字典里,如果不在字典里就会报错。
这时defaultdict就能派上用场了,defaultdict的作用是在于,当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值。
defaultdict接受一个工厂函数作为参数,如下来构造:
dict =defaultdict(factory_function)
factory_function可以是list、set、str等等,作用是当key不存在时,返回的是工厂函数的默认值,比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0。
相当于向字典中传入类型,默认值使用该类型的默认值,以避免出现键不在字典中的报错。
dict1 = defaultdict(int)
dict2 = defaultdict(set)
dict3 = defaultdict(str)
dict4 = defaultdict(list)
dict1[2] ='two'
print(dict1[1])
print(dict2[1])
print(dict3[1])
print(dict4[1])
print(dict1[2])
中间是空串的显示。
6. key的类型
value可以是任何类型,但key必须是不可变的对象,(比如元组中的对象也必须不可变)。可以通过哈希化检测,一个对象若能哈希化,则可以作为字典的键。
hash()
hash('string') # -6847109138761192205
hash((1,2,(2,3))) # 1097636502276347782
hash((1,2,[2,3])) # TypeError: unhashable type: 'list'
列表转换为元组则可以作为key.(tuple())
d = {}
d[tuple([1,2,3])] = 5
d # {(1, 2, 3): 5}
6. 集合set
无序,唯一
set():变成集合
{}: 创建集合
a = {2,2,2,1,3,4} # 创建集合,a is {1,2,3,4}
b = {3,5,6,7}
a | b # 集合求并集
a & b # 交集
# 增强运算
c = a.copy()
c |= b # c = c|b
c # {1, 2, 3, 4, 5, 6, 7}
{1,2,3} == {3,2,1} # True
常用函数:
7. 推导式
1.列表推导式:result = [expr for val in collection if condition]
等价于
result = []
for val in collention:
if condition: # 过滤条件
result.append(expr)
expr是计算结果,顺序是先做for循环,再判断,最后得到结果
## 过滤出字符大于2的单词并大写显示
strings = ['a','as','apple']
l = [x.upper() for x in strings if len(x)>2]
l # ['APPLE']
2.集合推导式:result = {expr for val in collection if condition}
## 得到字符串列表中字符串的长度集合
s = {len(x) for x in strings}
s # {1, 2, 5}
方法二:使用map函数,更简洁
map(function,iterable,…):对可迭代对象iterable中的每一个元素调用 function 函数,返回map对象。可以是自定义函数。
list(map(len,strings)) # [1, 2, 5]
set(map(len,strings)) # {1, 2, 5}
map,不止能传入一个可迭代对象做为参数。也可以传入多个。
ls1='ABC'
ls2='abc'
print(list(map(lambda x,y:x+y,ls1,ls2)))
# ['Aa', 'Bb', 'Cc']
3.字典推导式:result = {key_expr:value_expr for val in collection if condition}
4.嵌套列表推导式
对应于两重循环,for的顺序与嵌套for循环的顺序一致,由于可读性,一般不超过两重.
# 获得含有两个e以上的名字的列表
all_data = [['John','Steven'],['Juan','Pilar']]
l = [name for names in all_data for name in names if name.count('e') >= 2] # 对于每个小列表中的每个名字,如果e计数>=2,返回这个名字
l # ['Steven']
# 将含元组的列表扁平化为一个简单的列表
a = [(1,2,3),(4,5,6),(7,8,9)] # 只要能构成两重循环即可,不一定非是两重列表
l = [x for tup in a for x in tup] # 相对于嵌套循环里的append,推导式自动扩展列表
l # [1, 2, 3, 4, 5, 6, 7, 8, 9]
列表推导式中的列表推导式
最终结果是嵌套列表
a = [(1,2,3),(4,5,6),(7,8,9)]
l = [[x for x in tup] for tup in a] # 挨个返回的是列表,最终结果是嵌套列表
l # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
8.函数
def关键字声明是一个函数,return关键字返回值,遇到return即停止不再向下执行
def 函数名(参数表列):
函数体
return 返回值
- 参数包括:
普通参数(即位置参数);
关键字参数(定义时指定默认值(成为可选参数)的参数)。
关键字参数必须在位置参数后面。
所有参数都有参数名,调用时如果指明参数名则位置参数之间顺序任意,关键字参数之间顺序任意。 - 函数内变量的作用域:默认局部,函数执行完成时销毁。global关键字声明为全局变量
- 返回多个值:
return a,b,c
a,b,c = f()
实质是返回了一个元组,元组又被拆包。因为逗号分隔的值是元组的简易表示。因此可以直接用元组接收返回值:value = f()
也可以返回一个字典达到返回多个值的功能:return {‘a’:a,‘b’:b,‘c’:c}
dict = f()
print(dict)
{‘a’: 5, ‘b’: 6, ‘c’: 7}
例:将列表中的每个字符串规范化
import re # 正则表达式模块
states = [' Alabama','Georgia!','georgia','FLOrIda','south carolina##','West virginia?']
def normalize(string):
s = re.sub('[!#?]','',string).strip().title() # 连续使用多个函数,不能像R中管道函数,只能这么用
return s
l = list(map(normalize,states)) # map函数将函数应用到序列的每一个元素,类似于R的apply,sapply
print(l) # ['Alabama', 'Georgia', 'Georgia', 'Florida', 'South Carolina', 'West Virginia']
note:
- re.sub(pattern,repl,string,count = 0,flags = 0 ) 字符串替换,将string中符合pattern的字符替换为repl,count=0默认全部替换
- [!#?]是一个字符组,表示一个位置上可以出现的字符,一个位置上出现!或#或?则替换为空串,count=0替换全部符合的位置
- str.strip() 移除字符串两端的空格。类似的方法 .lstrip() 和 .rstrip() 。第一个是只删头,第二个是只删尾巴。
#.strip(char),.strip(string):移除字符串两端的字符或字符序列,实质是从头从尾遍历,如果字符包含在参数里就删除,遇到第一个不包含的字符就停止。
# 例如:.strip('0'),.strip('12'),.strip('hai'),只要外围碰到不需要删除的字符,屠杀就结束了。
- .title() :返回"标题化"的字符串,字符串中的所有单词都是以大写开始,其余字母均为小写
s = "this is string example....wow!!!"
print (s.title())
# This Is String Example....Wow!!!
lambda函数:
非常简单的函数可以不用写函数体,而用一句话表示,使用lambda关键字,该语句的结果就是返回值.
result = lambda x:函数体 using x (x是函数参数)
# 根据单词中不同字母的数量单词排序
words = ['foo','card','aaaa','abab']
words.sort(key=lambda x:len(set(list(x))))
words # ['aaaa', 'foo', 'abab', 'card']
Curry化
生成器和itertools模块:占坑,用到再填
9.异常处理
try:
要执行的可能出错的代码
except:
如果出错想采取的措施
(else:
如果try执行成功才要执行的代码)
(finally:
无论成功与否最后总要执行的代码)
# 输出浮点化,如果输入不能浮点化会报错,则except部分将执行,输出原值
x = 'a'
try:
print(float(x))
except:
print(x)
# a
注意:
1.如果只想处理某个异常类型,则在except后面加上特定异常类型,比如except ValueError:,其他异常类型仍会报错
2.可以同时处理多个异常类型,加括号写成元组,如except (ValueError,TypeError):
3.如果想无论报错与否最后都执行一部分代码,写到finally部分,比如程序与文件或数据库的连接最后总要关闭
4.如果想在try执行成功后才执行一些代码,写入else部分,作为对try执行成功的奖励
5.顺序一定是:try-except-(else)-(finally)
# 写入文件的异常处理
f = open('D:\\a.txt','w') # 建立文件对象
try:
f.write('123') # 向文件写入字符串
except:
print('Failed') # 如果失败
else:
print('Success') # 如果成功写入
finally:
f.close() # 最后关闭文件
10.文件与操作系统
- 创建文件对象以读取文件:f = open(path,mode=‘r’) 默认只读模式
模式 | 描述 |
---|---|
‘w’ | 只写模式:自动创建文件,覆盖同名文件 |
‘x’ | 同上,存在同名文件则报错 |
‘r+’ | 可读可写模式 |
‘a’ | 追加写模式,不存在就自动创建 |
还有两个是附加选项,添加到模式后面:
- b:以二进制形式,如’rb’
- t: 以文本模式(默认),如’rt’
- 读取操作:.read() .tell() .seek()
- 写入文件:write()
- 关闭文件对象:f.close()
path = 'D:\\a.txt' # 绝对路径
f = open(path,mode='r') # 创建文件对象,默认只读模式'r',可以看做元素是行的列表,需要显示关闭文件对象f.close()
for line in f:
print(line) # 打印每一行
f.close()
更简单的使用文件对象with,在with结束时自动关闭对象,区别在于结果不会直接显示在屏幕上,需要print
with open(path) as f:
lines = [line.rstrip() for line in f] # 去掉右边的换行符,因为每一行以换行符\n结尾,也包括在一行里面
lines # ["132'", 'abc/', 'opq.', '456,']
with open(path) as f:
lines = [line for line in f]
# 或 lines = f.readlines() 读取所有行到一个列表,每行是一个元素,大文件较占内存
lines # ["132'\n", 'abc/\n', 'opq.\n', '456,']
读取方法-文件句柄,即文件指针
使用这些方法要注意是针对字节计数的,而非ASCII码(比如汉字)可能占多个字节,要确保完整的字符被分开。
with open(path) as f:
print(f.tell()) # tell():给出句柄当前位置,是0
print(f.read(6)) # read(n):从当前句柄位置开始向后读取n个字节,同时推进文件句柄的位置,若无参数则读取所有字节,132'\na
print(f.tell()) # 7,即使用默认编码情况下需要多少字节对这6个字符进行解码,换行符\n占1个字节
print(f.seek(3)) # seek(n):改变句柄位置到第n个字节
# 检查系统的默认编码
import sys
sys.getdefaultencoding() # 'utf-8'
# 查看在某编码下字符占多少字节
len("132'\na".encode('utf-8')) # 'gbk'
编码方式
将字符串data解码为某种编码:data.decode(‘one encoding’)
常用编码方式:‘utf-8’,‘gbk’
open(path=,mode=’’,encoding=’’)中encoding可以方便将文件转换为另一种编码