(董付国)Python 学习笔记---Python序列(2)
1.1.9列表推导式
列表推导式使用非常简介的方式来快速生成满足特定需求的列表,代码具有非常强的可读性。
有三种等价方法:
>>> aList=[x*x for x in range(10)]
>>> aList
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>>
>>> aList=[]
>>> aList
[]
>>> for x in range(10):
... aList.append(x*x)
...
>>> aList
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>>
>>> aList=list(map(lambda x:x*x,range(10)))
>>> aList
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> aList=[2**x for x in range(64)]
>>> aList
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208, 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624, 2251799813685248, 4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 72057594037927936, 144115188075855872, 288230376151711744, 576460752303423488, 1152921504606846976, 2305843009213693952, 4611686018427387904, 9223372036854775808]
>>> sum(aList)
18446744073709551615
使用列表推导式实现嵌套列表的平铺:
>>> vec=[[1,2,3],[4,5,6],[7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
num:每个数字;elem:小列表;vec:大列表
相当于:
>>> vec=[[1,2],[3,4],[5,6],[7,8]]
>>> result = []
>>> for elem in vec:
... for num in elem:
... result.append(num)
...
>>> result
[1, 2, 3, 4, 5, 6, 7, 8]
如果不使用列表推导式,也可以这样:
>>> vec = [[1,2,3],[4,5,6],[7,8,9]]
>>> sum(vec,[])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> vec
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> from itertools import chain
>>> list(chain(*vec))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
*序列解包
列出当前文件夹下所有Python源文件
>>> import os
>>> [filename for filename in os.listdir('.')if filename.endswith(('.py','.pyw'))]
[]
过滤不符合条件的元素:
>>> aList=[-1,-4,6,7.5,-2.3,-9,-11]
>>> [num for num in aList if num>0]
[6, 7.5]
已知有一个包含一些同学成绩的字典,计算成绩的最高分,最低分,平均分,并查找所有最高分同学。
>>> scores={"zhang san":45,"li si":78,"wang wu":40,"zhou lin":96,"zhao qi":65,"sun ba":90,"zheng jiu":78,"wu shi":99,"dong shiyi":60}
>>> highest=max(scores.values())
>>> lowest=min(scores.values())
>>> average=sum(scores.values())*1.0/len(scores)
>>> highest,lowest,average
(99, 40, 72.33333333333333)
>>> highestPerson=[name for name,values in scores.items() if values==highest]
>>> lowestPerson=[name for name,values in scores.items() if values==lowest]
>>> highestPerson,lowestPerson
(['wu shi'], ['wang wu'])
在列表推导式中使用多个循环,实现多序列元素的任意组合,并且可以结合条件语句过滤特定元素
>>> [(x,y) for x in range(3) for y in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
>>> [(x,y) for x in range(1,4) for y in [3,1,4]]
[(1, 3), (1, 1), (1, 4), (2, 3), (2, 1), (2, 4), (3, 3), (3, 1), (3, 4)]
使用列表推导式实现矩阵转置:
>>> matrix=[[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> [[row[i] for row in matrix]for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
也可以使用内置函数来实现矩阵转置
>>> list(zip(*matrix)) #zip拉链函数,*序列解包,把最外面的括号去 掉
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
列表推导式中可以使用函数或复杂表达式
>>> def f(v):
... if v%2 == 0:
... v=v**2
... else:
... v=v+1
... return v
...
>>> [f(v) for v in [2,3,4,-1] if v>0]
[4, 4, 16]
>>> [v**2 if v%2 == 0 else v+1 for v in [2,3,4,-1] if v>0]
[4, 4, 16]
列表推导式支持文件对象迭代
with是一个上下文管理语句,可以自动的管理上下文资源。
使用列表推导式生成100以内的所有素数:
>>> [p for p in range(2,100) if 0 not in [p%d for d in range(2,int(p**0.5)+1)]]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
2-99的数字中是否存在除了1和他本自身之外的对2取余的值为0的数。
1.1.10使用列表实现向量运算
>>> import random
>>> x = [random.randint(1,100) for i in range(10)] #生成随机数
>>> x
[5, 47, 53, 78, 45, 21, 18, 17, 66, 20]
>>> list(map(lambda i:i+5,x)) #所有元素同时加5
[10, 52, 58, 83, 50, 26, 23, 22, 71, 25]
>>> x=[random.randint(1,10) for i in range(10)]
>>> y=[random.randint(1,10) for i in range(10)]
>>> import operator
>>> sum(map(operator.mul,x,y)) #向量内积
405
>>> sum(i*j for i,j in zip(x,y)) #向量内积
405
>>> list(map(operator.add,x,y)) #两个等长的向量对应元素相加
[14, 16, 15, 6, 11, 16, 11, 6, 13, 18]
>>> list(i+j for i,j in zip(x,y)) #两个等长的向量对应元素相加
[14, 16, 15, 6, 11, 16, 11, 6, 13, 18]
1.2 元组
- 元组和列表类似,但属于不可变序列,元组一旦创建,用任何方法都不可以修改元素。
- 元组的定义方式和列表相同,但定义时所有元素是放在一对圆括号“()”中,而不是方括号中。
- 使用“=”将一个元组赋值给变量
>>> a_tuple = ('a','b','mpilgrim','z','example')
>>> a_tuple
('a', 'b', 'mpilgrim', 'z', 'example')
>>> a=(3)
>>> a
3
>>> a=(3,) #包含一个元素的元组,最后必须多写一个逗号
>>> a
(3,)
>>> a=3, #也可以这样创建元组
>>> a
(3,)
>>> x = () #空元组
>>> x
()
使用tuple函数将其他序列转换为元组
>>> tuple('abcdefg')
('a', 'b', 'c', 'd', 'e', 'f', 'g')
>>> aList=[-1,-4,6,7.5,-2.3,9,-11]
>>> aList
[-1, -4, 6, 7.5, -2.3, 9, -11]
>>> tuple(aList)
(-1, -4, 6, 7.5, -2.3, 9, -11)
>>> s=tuple()
>>> s
()
使用del可以删除元组对象,不能删除元组中的元素
>>> s=tuple(aList)
>>> s
(-1, -4, 6, 7.5, -2.3, 9, -11)
>>> del s(1)
File "<stdin>", line 1
SyntaxError: can't delete function call
>>> del s
>>> s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 's' is not defined
1.2.2元组与列表的区别
- 元组中的数据一旦定义就不允许更改。但是元组中的元素是列表的话,列表可以进行更改。
- 元组没有append()、extend()和insert()等方法,无法向元组中添加元素。
- 元组中没有remove()或pop()方法,也无法对元组元素进行del操作,不能从元组中删除元素。
- 从效果上来看,tuple()冻结列表,list()融化元组。
>>> x[0]=6
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> del x[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object doesn't support item deletion
>>> x[2]
[3, 4, 5]
>>> x[2].append(6)
>>> x
(1, 2, [3, 4, 5, 6])
元组的优点:
- 元组的速度比列表更快。如果定义了一系列常量值,而所需做的仅是对它进行遍历,那么一般使用元组而不用列表。(遍历速度:集合>元组>列表)
- 元组对不需要改变的数据进行“写保护”将使得代码更加安全。
- 元组可用作字典键(特别是包含字符串、数值和其他元组这样的不可变数据的元组)。列表永远不能当作字典键使用,因为列表不是不可变的。
1.2.3 序列解包
- 可以使用序列解包功能对多个变量同时赋值
>>> x,y,z = 1,2,3 #多个变量同时赋值
>>> v_tuple = (False,3.5,'exp')
>>> (x,y,z) = v_tuple
>>> x,y,z = range(3) #可以对range对象进行序列解包
>>> x,y,z = iter([1,2,3]) #使用迭代器对象进行序列解包
>>> x,y,z = map(str,range(3)) #使用可迭代的map对象进行序列解包
>>> a,b=b,a #交换两个变量的值
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
>>> x,y,z=sorted([1,3,2]) #sorted()函数返回排序后的列表
>>> a,b,c = 'ABC' #字符串也支持序列解包
>>> x = [1,2,3,4,5,6]
>>> x[:3]=map(str,range(5)) #切片也支持序列解包
>>> x
['0', '1', '2', '3', '4', 4, 5, 6]
注:连续的切片操作,左右两边可以数量不一样;但是,切片不连续,左右两边元素个数必须一样。
- 序列解包对于列表和字典同样有效
>>> s = {'a':1,'b':2,'c':3}
>>> b,c,d = s.items()
>>> b
('a', 1)
>>> b,c,d = s #使用字典时不用考虑太多元素的顺序
>>> b
'a'
>>> b,c,d = s.values()
>>> print(b,c,d)
1 2 3
>>> b,c,d = s
>>> print(b,c,d)
a b c
- 序列解包遍历多个序列
>>> keys = ['a','b','c','d']
>>> values = [1,2,3,4]
>>> for k,v in zip(keys,values):
... print((k,v),end=' ')
...
('a', 1) ('b', 2) ('c', 3) ('d', 4) >>>
- 使用序列解包遍历enumerate对象
>>> x = ['a','b','c']
>>> for i,v in enumerate(x):
... print('The value on position {0} is {1}'.format(i,v))
...
The value on position 0 is a
The value on position 1 is b
The value on position 2 is c
在循环遍历元组时,{0}和{1}会分别被i,v所替换。
>>> aList = [1,2,3]
>>> bList = [4,5,6]
>>> cList = [7,8,9]
>>> dList = zip(aList,bList,cList)
>>> for index,value in enumerate(dList):
... print(index,':',value)
...
0 : (1, 4, 7)
1 : (2, 5, 8)
2 : (3, 6, 9)
- Python 3.5还支持下面用法的序列解包
>>> print(*[1,2,3],4,*[5,6])
1 2 3 4 5 6
>>> *range(4),4 #逗号的作用可以使解包后的序列组成元组
(0, 1, 2, 3, 4)
>>> {*range(4),4,*(5,6,7)} #加"{}"是用来构建集合的方法
{0, 1, 2, 3, 4, 5, 6, 7}
>>> {'x':1,**{'y':2}} #"**"用来解包字典
{'x': 1, 'y': 2}
1.2.4 生成器推导式
- 生成器推导式的结果是一个生成器对象。使用生成器对象的元素时,可以根据需要将其转化为列表或元组,也可以使用生成器对象_next_()方法或内置函数next()进行遍历,或者直接用for循环将其作为迭代器对象来使用。
- 生成器对象具有惰性求值的特点(map,zip,filter,enumerate…),只在需要时生成新元素,比列表推导式具有更高的效率,空间占用非常少,尤其适合大数据处理的场合。
- 不管用哪种方法访问生成器对象,都无法在此访问已访问过的元素。
1.使用生成器对象_next_()方法或内置函数next()进行遍历
>>> g._next_() #使用生成器对象的_next_()方法获取元素
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'generator' object has no attribute '_next_'
>>> g = ((i+2)**2 for i in range(10)) #重新创建生成器象
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
4 >>> g.__next__() #使用生成器对象的_next_()方法获取元素
9
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
16
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
25
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
36
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
49
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
64
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
81
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
100
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
121
>>> g.__next__() #使用生成器对象的_next_()方法获取元素
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
注:过程中遇到了“AttributeError: ‘generator’ object has no attribute 'next’”的Bug,原因是:把“_ _ next_ ”写成了“ next _”,此处没有空格,为了方便大家看到是两个。
参考的是某位前辈的帖子,在这里附上他的链接:https://blog.csdn.net/marysa/article/details/25141877
- 使用for循环直接迭代生成器对象中的元素
>>> g = ((i+2)**2 for i in range(10)) #构建生成器
>>> for item in g: #使用for循环直接遍历生成器对象中的元素
... print(item,end=' ')
...
4 9 16 25 36 49 64 81 100 121 >>>
>>>
>>> x = filter(None,range(20)) #filter对象也具有类似的特点
>>> 5 is x
False
>>> 5 in x
True
>>> 2 in x #不可再次访问已访问过的元素
False
>>> 7 in x
False
>>> 10 in x
False
>>>
>>> x = map(str,range(20)) #map对象也具有类似的特点
>>> '0' in x
True
>>> '0' in x
False
第一次访问5的时候已经遍历过2,所以2不在,遍历2的时候,因为后面都遍历过了没有2,所以都没有了。
1.3 字典
- 字典是无序可变序列。
- 定义字典时,每个元素的键和值用冒号分隔,元素之间用逗号分隔,所有的元素放在一个大括号“{}”中。
- 字典中的键可以为任意不可变数据,比如整数、实数、复数、字符串、元组等等。
- globals()返回包含当前作用域内所有全局变量的值和字典。
- locals()返回包含当前作用域内所有局部变量和值的字典。
1.3.1字典创建与删除
- 使用‘=’将一个字典赋值给一个变量
>>> a_dict = {'server':'db.diveintopython3.org','database':'mysql'}
>>> a_dict
{'server': 'db.diveintopython3.org', 'database': 'mysql'}
>>> x = {} #空字典
>>> x
{}
- 使用dict利用已有数据创建字典:
>>> key = ['a','b','c','d']
>>> values=[1,2,3,4]
>>> dictionary = dict(zip(key,values))
>>> dictionary
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> x = dict() #空字典
>>> x
{}
- 使用dict根据给定的键、创建字典:
>>> d = dict(name = 'Dong',age = 37)
>>> d
{'name': 'Dong', 'age': 37}
- 以给定内容为键,创建值为空的字典
>>> adict = dict.fromkeys(['name','age','sex'])
>>> adict
{'name': None, 'age': None, 'sex': None}
- 可以使用del删除整个字典
1.3.2 字典元素的读取
- 以键作为下标可以读取字典元素,若键不存在则抛出异常(程序就崩溃了,不向下执行,影响程序的健壮性,不建议用,一般使用get)
>>> adict = {'name':'Dong','sex':'male','age':'37'}
>>> adict['name']
'Dong'
>>> adict['tel'] #键不存在,抛出异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'tel'
1.3.3 字典元素的添加与修改
- 使用字典对象的get方法获取指定键对应的值,并且可以在键不存在的时候返回指定值。
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': '37'}
>>> print(adict.get('address'))
None
>>> print(adict.get('address','SDIBT'))
SDIBT
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': '37'}
>>> adict['score'] = adict.get('score',[])
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': '37', 'score': []}
>>> adict['score'].append(98)
>>> adict['score'].append(97)
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': '37', 'score': [98, 97]}
- 使用字典对象的items()方法可以返回字典的键、值对列表
- 使用字典对象的keys()方法可以返回字典的键列表
- 使用字典对象的values()方法可以返回字典的值列表
>>> adict = {'name':'Dong','sex':'male','age':37}
>>> for item in adict.items(): #输出字典中所有元素
... print(item)
...
('name', 'Dong')
('sex', 'male')
('age', 37)
>>> for key in adict: #不加特殊说明,默认输出键
... print(key)
...
name
sex
age
>>> for key,value in adict.items(): #序列解包法
... print(key,value)
...
name Dong
sex male
age 37
>>> adict.keys() #返回所有键
dict_keys(['name', 'sex', 'age'])
>>> adict.values() #返回所有值
dict_values(['Dong', 'male', 37])
- 当以指定键为下标为字典赋值时,若键存在,则可以修改该键的值;若不存在,则表示添加一个键、值对。
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': 37}
>>> adict['age'] = 38 #修改元素值
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': 38}
>>> adict['address']='SDIBT' #增加新元素
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': 38, 'address': 'SDIBT'}
- 使用字典对象的update方法将另一个字典的键、值对添加到当前字典对象
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': 38, 'address': 'SDIBT'}
>>> adict.items()
dict_items([('name', 'Dong'), ('sex', 'male'), ('age', 38), ('address', 'SDIBT')])
>>> adict.update({'address':'Linfen','level':'one'})
>>> adict
{'name': 'Dong', 'sex': 'male', 'age': 38, 'address': 'Linfen', 'level': 'one'}
>>> adict.items()
dict_items([('name', 'Dong'), ('sex', 'male'), ('age', 38), ('address', 'Linfen'), ('level', 'one')])
- 使用del删除字典中指定键的元素
- 使用字典对象的clear()方法来删除字典中所有元素
- 使用字典对象pop()方法删除并返回指定键的元素
- 使用字典对象的popitem()方法删除并返回字典中的一个元素
1.3.4 字典应用案列
- 首先生成包含1000个随机字符的字符串,然后统计每个字符的出现次数。
>>> import string
>>> import random
>>> x = string.ascii_letters + string.digits + string.punctuation
>>> y = [random.choice(x) for i in range(20)] #这里也可以换成圆括号增加效率
>>> z = ''.join(y)
>>> d = dict() #使用字典保存每个字符出现次数
>>> for ch in z:
... d[ch] = d.get(ch,0) + 1
...
>>> d
{'I': 1, 'D': 1, 'A': 2, 'B': 1, 'M': 1, ';': 1, '%': 1, 'V': 1, 'j': 1, '|': 1, 'Q': 1, '1': 1, 'O': 1, 'P': 1, 'r': 1, '-': 2, '(': 1, '2': 1}
1.3.5 有序字典
- Python内置字典是无序的,如果需要一个可以记住元素插入顺序的字典,可以使用collections.OrderedDict。
>>> x = dict() #无序字典
>>> x['a'] = 3
>>> x['b'] = 5
>>> x['c'] = 8
>>> x
{'a': 3, 'b': 5, 'c': 8}
>>> import collections
>>> x = collections.OrderedDict() #有序字典
>>> x['a'] = 3
>>> x['b'] = 5
>>> x['c'] = 8
>>> x
OrderedDict([('a', 3), ('b', 5), ('c', 8)])
1.3.6 字典推导式
>>> s = {x:x.strip() for x in (' he ','she ',' I')}
>>> s
{' he ': 'he', 'she ': 'she', ' I': 'I'}
>>> for k,y in s.items():
... print(k,':',v)
...
he : c
she : c
I : c
>>> {i:str(i) for i in range(1,5)}
{1: '1', 2: '2', 3: '3', 4: '4'}
>>> x = {'A','B','C','D'}
>>> y = {'a','b','c','d'}
>>> {i:j for i,j in zip(x,y)}
{'B': 'b', 'C': 'd', 'D': 'c', 'A': 'a'}

浙公网安备 33010602011771号