赞
踩
特性
1️⃣:列表元素按顺序有序排列
2️⃣:索引映射唯一一个数据
3️⃣:可以存储重复数据
4️⃣:任意数据类型混存
5️⃣:根据需要动态分配和回收内存
方法 增删改查
list.append(x) 元素x添加至列表尾部
list.extend(L) 将列表L中所有元素添加至列表尾部
list.insert(index,x) 在列表指定位置index处添加元素x
list.remove(x) 在列表中删除首次出现的指定元素x
list.pop([index]) 删除并返回列表对象指定位置index的元素,默认为最后一个元素
list.clear() 删除列表中所有元素,但保留列表对象,Python3.x新增功能
list.index(x) 返回第一个值为x的元素下标,若不存在,则抛出异常
list.count(x) 返回指定元素x在列表中出现的次数
list.reverse() 对列表元素进行原地翻转(逆置)
list.sort() 对列表元素进行原地排序
list.copy() 返回列表对象的浅复制,Python3.x新增功能
创建
1、使用中括号[],元素间用逗号分隔
2、调用内置函数list(),可以使用list()函数将元组、range对象、字符串或其他类型的可迭代对象类型的数据转换为列表。**内置函数range()**语法为range([start,] stop [,step])
删除
当不再使用时,使用del命令删除整个列表,如果列表对象所指向的值不再有其他对象指向,Python将同时删除该值。
增加
1、可以使用**+运算符来实现将元素添加**到列表中的功能。alist=alist+[7]
2、使用列表对象的append()方法,原地修改列表,是真正意义上的在列表尾部添加元素,速度较快,也是推荐使用的方法。
3、使用列表对象的extend()方法可以将另一个迭代对象的所有元素添加至改列表对象尾部。通过extend()方法来增加列表元素也不改变其内存地址,属于原地操作。alist.extend([2,3,4])
4、使用列表对象的insert(index,x)方法将元素添加至列表的指定位置。
5、使用乘法来扩展列表对象,将列表与整数相乘,生成一个新列表,新列表是原列表中元素的重复。
alist=[3,4,5] blist=alist id(alist)=id(blist) alist=alist*3 则id(alist)!=id(blist)
该操作实际上是创建了一个新列表,而不是真的扩展了原列表。该操作同样适用于字符串和元组,并具有相同的特点。
需要注意的是,**当使用*运算符将包含列表的列表进行重复并创建新列表时,并不创建元素的复制,而是创建已有对象的引用。**因此,当修改其中一个值时,相应的引用也会被修改。例如:
x = [[None] * 2 ] * 3
x
[[None,None],[None,None],[None,None]]
x[0][0]=5
x
[[5,None],[5,None],[5,None]]
Python采用的是基于值的自动内存管理方式,当为对象修改值时,并不是真的直接修改变量的值,而是使变量指向新的值,这对所有变量都是一样的。对于列表、集合、字典等可变序列类型而言,情况稍微复杂一些。以列表为例,列表中包含的是元素值的引用,而不是直接包含元素值。
如果是直接修改序列变量的值,则与Python普通的情况是一样的;而如果是通过下标来修改序列中元素的值或者通过可变序列对象自身提供的方法来增加和删除元素时,序列对象在内存中的起始地址是不变的(原地操作),仅仅是被改变值的元素地址发生变化。
a=[1,2,4] b=[1,2,3]
a=b
False
id(a)=id(b)
False
id(a[0])=id(b[0])
True
a=[1,2,3]
id(a)=25289752
a.append(4)
id(a)=25289752
a.remove(3)
a=[1,2,4]
id(a)=25289752
a[0]=5
a=[5,2,4]
id(a)=25289752
元素的删除
1、使用del命令删除列表中的指定位置上的元素。del命令也可以直接删除整个列表。
2、使用列表的pop(index)方法删除并返回指定index(默认为最后一个)位置上的元素,如果给定的索引超出了列表的范围,则抛出异常。
3、使用列表对象的remove(x)方法删除首次出现的指定元素x,若列表无要删除的元素,则抛出异常。
注意:,由于列表的自动内存管理功能,在删除或增加列表元素时,Python会自动对列表内存进行收缩并移动列表元素以保证所有的元素之间没有空隙。每当插入或删除一个元素后,该元素位置后面所有元素的索引就都改变了。因此使用“循环+remove()”的方法,但具体操作时很有可能会出现意料之外的错误。
元素访问与计数
1、可以使用下标直接访问列表中的元素(可查可改)。若下标不存在,则抛出异常提示下标越界。
2、使用列表对象的index()方法可以获取指定元素首次出现的下标,语法为index(value,[start,[stop]]) ,若不存在,则抛出异常提示。
3、如果需要知道指定元素x在列表中出现的次数,可以使用列表对象的count(x)方法进行统计。该方法也可以用于元组、字符串以及range对象
如果需要判断列表中是否存在指定的值,可以使用前面介绍的count()方法。或者,使用更简洁的in关键字来判断一个值是否存在于列表中,返回结果为True或False。
alist = [1,2,3] blist = [‘a’,‘b’,‘c’]
3 in alist
True
(3,‘a’) in zip(alist,blist)
True(在Python3.x中是False)
zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。在Python3.x中为减少内存,zip()返回的是个对象。
for a,b in zip(alist,blist):
print(a,b)
1 a
2 b
3 c
关键字in和not in也可以用于其他可迭代对象,包括元组、字典、range对象、字符串、集合等,常用在循环语句中对序列或其他可迭代对象中的元素进行遍历。
切片适用于列表、元组、字符串、range对象等类型
切片使用2个冒号分隔的3个数字来完成:第一个数字表示切片开始位置(默认为0),第二个数字代表切片截至(但不包含)位置(默认为列表长度),第三个数字表示切片的步长(默认为1),当步长省略时可以顺便省略最后一个冒号。alist[::]
可以使用切片来截取列表中的任何部分,得到一个新列表。可使用切片操作来快速实现很多目的,例如原地修改列表内容,列表元素的增删改查CRUD以及元素的替换等操作都可以通过切片来实现,并且不影响列表对象内存地址。(原地操作)
切片返回的是列表元素的浅复制,与列表对象的直接赋值并不一样。
blist = alist[::] #浅复制
浅复制相同的列表但不指向同一块内存。
列表排序
1、使用列表对象自身提供的sort()方法进行原地排序,该方法支持多种不同的排序方式。
import random
random.shuffle(alist) #打乱顺序
alist.sort() #默认为升序排序
alist.sort(reverse=True) #降序排序
alist.sort(key=lambda x: len(str(x))) #自定义排序
2、也可以使用内置函数sorted()对列表进行排序,与列表对象的sort()方法不同,内置函数sorted()返回新列表,并不对原列表进行任何修改。(非原地操作)
sorted(alist)
3、可以使用列表对象的reverse()方法将所有元素原地逆置。
sorted(alist,reverse=True)
4、alist=[random.randint(50,100) for i in range(10)] #返回10个50~100之间的任意整数
5、Python提供了内置函数reversed()支持对列表元素进行逆序排列,与列表对象的reverse()方法不同,内置函数reversed()不对原列表做任何修改,而是返回一个逆序排列后的迭代对象。
alist=[1,2,3,4,5,6,7]
newlist=reversed(alist)
print(alist) #返回一个可迭代对象
list(alist) #返回一个列表
[7,6,5,4,3,2,1]
for i in newlist:
print(i,end=’’)
上面代码中最后的for循环没有输出任何内容,因为在之前的list()函数执行时,迭代对象已遍历结束,需要重新创建迭代对象才能再次访问其内容。
newlist=reversed(alist)
for i in newlist:
print(i,end=’’)
7 6 5 4 3 2 1
序列操作的常用内置函数
1、cmp(序列1,序列2):对两个列表进行比较,若第一个列表大于第二个,则结果为1,相反则为-1,元素完全相同则结果为0,类似于==、>、<等关系运算符,但和is、is not不一样。
比较大小的时候,元组内的数据会连接(合并)成一个整体数据,比如 (1, 20) 会当作 120 进行处理。如果元组长度不同,而且小元组和大元组的前几项对应相等,则默认大元组大于小元组,与大元组剩余项的值无关。
但是在Python3.x中不再支持cmp()函数,可以直接使用关系运算符来比较数值或者序列大小。即>、<、=
2、len(列表):返回列表中的元素个数,同样适用于元组、字典、集合、字符串、range对象等各种可迭代对象。count()是查询某个元素的个数。
3、max(列表)、min(列表):返回列表中的最大或最小元素,同样适用于元组、字符串、集合、range对象、字典等,要求所有元素之间可以进行大小比较。
==注意:==在对字典进行操作时,默认是对字典的“键”进行计算,如果需要对字典中的“值”进行计算,则需要使用字典对象中的value()方法明确说明。例如:
a={1:1,2:5,3:8}
max(a)
3
max(a.value)
8
4、sum(列表):对数值型列表的元素进行求和运算,对非数值型列表运算则出错,同样适用于数值型元组、集合、range对象、字典等。同样地,对于字典来说,默认是对字典的“键”进行计算。
5、zip(列表1,列表2,…):将多个列表或元组对应位置的元素组合为元组,并返回包含这些元组的列表(Python2.x)或zip对象(Python3.x)。结果不一样
alist=[1,2,3]
blist=[3,4,5]
clist=zip(a,b)
clist
<zip object at 0x0000000003728908>
list(clist)
[(1,3),(2,4),(3,5)] #Python3.x
6、enumerate(列表):枚举列表、元组或其他可迭代对象的元素,返回枚举对象,枚举对象中每个元素是包含下标和元素值的元组。该函数对于字符串、字典同样有效。
for item in enumerate(clist): print(item) (0,(1,3)) (1,(2,4)) (2,(3,5)) for index,ch in enumerate('SDIBT'): print((index,ch),end=',') (0,'S'),(1,'D'),(2,'I'),(3,'B'),(4,'T'), a {1:1,2:5,3:8} for i,v in enumerate(a): print(i,v) 0 1 1 2 2 3 for i,v in enumerate(a.value): print(i,v) 0 1 1 5 2 8
列表推导式可以说是Python程序开发时应用最多的技术之一
例如:alist=[x*x for x in range(10)] 等价于
alist=[]
for x in range(10):
alist.append(x*x)
freshfruit=['banana','loganberry','passion fruit']
alist=[w.strip() for w in freshfruit]
等价于
freshfruit=['banana','loganberry','passion fruit']
for i,v in enumerate(freshfruit):
freshfruit[i]=v.strip()
同时也等价于
freshfruit=['banana','loganberry','passion fruit']
freshfruit=list(map(str.strip,freshfruit))
1、使用列表推导式实现嵌套列表的平铺。
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]
2、过滤不符合条件的元素。
在列表推导式中可以使用if子句来筛选,只在结果列表中保留符合条件的元素。例如:
(1)下面的代码可以列出当前文件夹下所有Python源文件:
import os
[filename for filename in os.listdir(’.’) if filename.endswith(’.py’)]
(2)下面的代码用于从列表中选择符合条件的元素组成新的列表:
alist=[-1,-4,6,7.5,-2.3,9,-11]
[i for i in alist if i>0]
[6,7.5,9]
(3)已知有一个包含一些同学成绩的字典,计算成绩的最高分、最低分和平均分,并查找所有最高分同学,代码可以编写为如下:
scores={“Zhang San”:45,“Li Si”:78,“Wang Wu”:40,“Zhou Liu”: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())/len(scores)
highestPerson=[name for name,score in scores.items() if score==highest]
3、在列表推导式中使用多个循环,实现多序列元素的任意组合,并且可以结合条件语句过滤特定元素。
[(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 [1,2,3] for y in [3,1,4] if x!=y] #过滤特定元素
[(1,3),(1,4),(2,3),(2,1),(2,4),(3,1),(3,4)]
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]]
也可以使用内置函数zip()和list()来实现矩阵转置:
list(zip(* matrix))
[(1,5,9),(2,6,10),(3,7,11),(4,8,12)]
5、列表推导式中可以使用函数或复杂表达式。
def f(v):
if v%2==0:
v=v**2
else:
v=v+1
return v
print([f(v) for v in [2,3,4-1] if v>0])
[4,4,16]
*print([v*2 if v%2==0 else v+1 for v in [2,3,4,-1] if v>0])
[4,4,16]
6、列表推导式支持文件对象迭代。
fp=open(‘C:\install.log’,‘r’)
print([line for line in fp])
fp.close()
7、使用列表推导式生成100以内的所有素数。
[p for p in range(2,100) if 0 not in [p%d for d in range(2,int(sqrt§)+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]
列表支持与整数的乘法运算,表示列表元素进行重复并生成新列表,不对原列表进行任何修改。
列表之间的加法运算表示列表元素的合并,生成新列表,而不是向量意义的加法。
[1,2,3]+[4,5,6]
[1,2,3,4,5,6]
然而,向量运算经常涉及这样的操作,例如向量所有分量同时加、减、乘、除同一个数,或者向量之间的加、减、乘运算,Python列表对象本身不支持这样的操作,不过可以借助于内置函数和标准库operator中的方法来实现,或者使用扩展库numpy实现更加强大的功能。
例如:
import operator
sum(map(operator.mul,x,y)) #向量内积
sum((i*j for i,j in zip(x,y))) #向量内积
list(map(operator.add,x,y)) #两个等长的向量对应元素相加
与列表类似,元组也是一个重要的序列结构,但与列表不同的是,元组属于不可变序列。元组一旦创建,用任何方法都不可以修改其元素的值,也无法为元组增加或删除元素。
1、使用=将一个元组赋值给变量,就可以创建一个元组变量(与列表类似)。
a_tuple=(‘a’, )
注意,如果要创建只包含一个元素的元组,只把元素放在圆括号里是不行的,还需要在元素后面加一个“,”,而创建包含多个元素的元组则没有这个限制。
2、如同使用list()函数序列转换为列表一样,也可以使用tuple()函数将其他类型序列转换为元组。
print(tuple(‘abcdefg’))
(‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’)
3、对于元组而言,只能使用del命令删除整个元组对象,而不能只删除元组中的部分元素,因为元组属于不可变序列。
1、元组没有提供append()、extend()和insert()等方法,无法向元组中添加元素;同样,元组也没有remove()和pop()方法,也不支持对元组元素进行del操作,不能从元组中删除元素,只能使用del命令删除整个元组。
2、元组也支持切片操作,但是只能通过切片来访问元组中的元素,而不支持使用切片来修改元组中元素的值,也不支持使用切片操作来为元组增加或删除元素。
3、从效果上看,tuple()函数可以看作是在冻结列表并使其不可变,而list()函数是在融化元组使其可变。
4、元组的访问和处理速度比列表更快。可以认为元组对不需要修改的数据进行了“写保护”,从而在实现上不允许修改其元素值,从而使代码更加安全。
5、另外,作为不可变序列,与整数、字符串一样,元组可用作字典的键,而列表则永远都不能当做字典键使用,因为列表不是不可变的。
6、最后,虽然元组属于不可变序列,其元素的值是不可改变的,但是如果元组中包含可变序列,情况就略有不同。
x=([1,2],3)
x[0][0]=5
x
([5,2],3)
x[0].append(8)
x
([5,2,8],3)
x[0]=x[0]+[10] #则错误,x仍为([5,2,8],3)
在实际开发中,序列解包是非常重要和常用的一个用法,可以使用非常简洁的形式完成复杂的功能,大幅度提高了代码的可读性,并且减少了程序员的代码输入量。
例如,1.可以使用序列解包功能对多个变量同时进行赋值:
x,y,z=1,2,3
print(x,y,z)
1 2 3
再如:
a_tuple=(False,3.5,‘exp’)
(x,y,z)=a_tuple
print(x,y,z)
False 3.5 exp
或者:
x,y,z=a_tuple
序列解包也可以用于列表和字典,但是对字典使用时,默认是对字典“键”操作,如果需要对“键-值对”操作,需要使用字典的items()方法说明,如果需要对字典“值”操作,则需要使用字典的value()方向明确指定。对字典操作时,不需要对元素的顺序考虑过多。
下面的代码演示了列表与字典的序列解包操作:
a=[1,2,3]
b,c,d=a
s={'a':1,'b':2,'c':3}
b,c,d=s.items()
b
('c',3)
b,c,d=s
b
'c'
b,c,d=s.values()
print(b,c,d)
1 3 2
使用序列解包可以很方便地同时遍历多个序列。
keys=['a','b','c','d']
values=[1,2,3,4]
for k,v in zip(keys,values):
print(k,v)
a 1
b 2
c 3
d 4
在调用函数时,在实参前面加上一个星号(*)也可以进行序列解包,从而实现将序列中的元素值依次传递给相同数量的形参。
print(*[1],*[2],3,*[4,5])
1 2 3 4 5
def demo(a,b,c,d):
print(a,b,c,d)
demo(**{'a':1,'c':3},**{'b':2,'d':4})
1 2 3 4
*range(4),4
(0,1,2,3,4)
[*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}
从形式看,生成器推导式与列表推导式非常接近,只是生成器推导式使用圆括号而不是列表推导式所使用的方括号。
与列表推导式不同的是,生成器推导式的结果是一个生成器对象,而不是列表,也不是元组。
使用生成器对象的元素时,可以根据需要将其转化为列表或元组,也可以使用生成器对象的next()方法(Python2.x)或**__next__()方法(Python3.x)进行遍历,或者直接将其作为迭代器对象来使用**。
但是不管用哪种方法访问其元素,当所有的元素访问结束之后,如果需要重新访问其中的元素,必须重新创建该生成器对象。
g=((i+2)**2 for i in range(10)) g <generator object <genexpr> at 0x0000027184329AF0> tuple(g) #转化为元组 (4, 9, 16, 25, 36, 49, 64, 81, 100, 121) tuple(g) () #元素已经遍历结束 g=((i+2)**2 for i in range(10)) #重新创建生成器对象 list(g) #转化为列表 [4,9,16,25,36,49,64,81,100,121] g=((i+2)**2 for i in range(10)) g.__next__() #单步迭代,在Python3.x中 4 g.__next__() 9 g.__next__() 16 g=((i+2)**2 for i in range(10)) for i in g: #直接循环迭代 print(i,end='') 4 9 16 25 36 49 64 81 100 121
1️⃣:字典是**“键-值对”的无序可变序列**,字典中的每个元素包含两部分:“键”和“值”。定义字典时,每个元素的“键”和“值”用冒号分隔,相邻元素之间用逗号分隔,所有的元素放在一对大括号“{”和“}”中。
2️⃣:字典中的**“键”可以是Python中任意不可变数据,例如整数、实数、复数、字符串、元组等**,但不能使用列表、集合、字典作为字典的“键”,因为这些类型的对象是可变的。
3️⃣:字典中的**“键”不允许重复,而“值”是可以重复的**。
4️⃣:可以使用内置函数globals()返回和查看包含当前作用域内所有全局变量和值的字典,使用内置函数locals()返回包含当前作用域内所有局部变量和值的字典。
a=(1,2,3,4,5) #全局变量
b='hello world.' #全局变量
def demo():
a=3 #局部变量
b=[1,2,3] #局部变量
print('locals:',locals())
print('globals:',globals())
demo()
locals: {'a': 3, 'b': [1, 2, 3]}
globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__
': {}, '__builtins__': <module 'builtins' (built-in)>, 'a_tuple': (False, 3.5, 'exp'), 'x': False, 'y': 3.5, 'z': 'exp', 'g': <generator object <genexpr> at 0x000002
7184329BD0>, 'a': (1, 2, 3, 4), 'b': 'hello world', 'demo': <function demo at 0x0000027184243E20>}
创建
1、使用=将一个字典赋值给一个变量即可创建一个字典变量。
a_dict={‘server’:‘db.diveintopython3.org’,‘database’:‘mysql’}
2、可以**使用内置函数dict()**通过已有数据快速创建字典:
keys=[‘a’,‘b’,‘c’,‘d’]
values=[1,2,3,4]
dictionary=dict(zip(keys,values))
print(dictionary)
{‘a’:1,‘c’:3,‘b’:2’,‘d’:4}
x=dict() #空字典
x={} #空字典
3、或者**使用内置函数dict()根据给定的“键-值对”**来创建字典:
d=dict(name=‘Dong’,age=37)
d
{‘age’:37,‘name’:‘Dong’}
4、还可以以给定内容为“键”,创建“值”为空的字典:
adict=dict.fromkeys([‘name’,‘age’,‘sex’])
adict
{‘age’:None,‘name’:None,‘sex’:None}
删除
当不需要某个字典时,可以使用del命令删除整个字典,也可以使用del命令删除字典中指定的元素。
元素读取
1、与列表和元组类似,可以使用下标的方式来访问字典中的元素,但不同的是字典的下标是字典的“键”,而列表和元组访问时下标必须为整数值。使用下标的方式访问字典“值”时,若指定的“键”不存在则抛出异常。
a_dict={‘name’:‘Dong’,‘sex’:‘male’,‘age’:37}
a_dict[‘name’]
‘Dong’
2、比较推荐的也是更加安全的字典元素访问方式是字典对象的get()方法。使用字典对象的get()方法可以获取指定“键”对应的“值”,并且可以在指定“键”不存在的时候返回指定值,如果不指定,则默认返回None。
print(a_dict.get('address'))
None
print(a_dict.get('address','SDIBT')) #键不存在时返回指定值
SDIBT
a_dict['score']=a_dict.get('score',[]) #创建新的“键”,对应的值为列表序列
a_dict['score'].append(98) #新增
a_dict['score'].append(97) #新增
a_dict
{'age':37,'score':[98,97],'name':'Dong','sex':'male'}
3、另外,使用字典对象的items()方法可以返回字典的==“键-值对”列表==,使用字典对象的keys()方法可以返回字典的==“键”列表==,使用字典对象的values()方法可以返回字典的==“值”列表==。
a_dict={'name':'Dong','sex':'male','age':37} for item in a_dict.items(): print(item) ('age',37) ('name','Dong') ('sex','male') for key in a_dict: print(key) age name sex for key,value in a_dict.items(): print(key,value) age 37 name Dong sex male
修改
1、当以指定“键”为下标为字典元素赋值时,若该“键”存在,则表示修改该“键”的值;若不存在,则表示添加一个新的“键-值对”,也就是添加一个新元素。
a_dict['age']=38
a_dict
{'age':38,'name':'Dong','sex':'male'}
a_dict['address']='SDIBT'
a_dict
{'age':38,'address':'SDIBT','name':'Dong','sex':'male'}
2、使用字典对象的update()方法将另一个字典的“键-值对”一次性全部添加到当前字典对象,如果两个字典中存在相同的“键”,则以另一个字典中的“值”为准对当前字典进行更新。
a_dict.update({'a':'a','b':'b'})
a_dict
{'a':'a','score':[98,97],'name':'Dong','age':37,'b':'b','sex':'male'}
当需要删除字典元素时,①可以根据具体要求使用del命令删除字典中指定“键”对应的元素,或者②也可以使用字典对象的clear()方法来删除字典中所有元素,还可以③使用字典对象的pop()方法删除并返回指定“键”的元素,或者④使用字典对象的popitem()方法删除并返回字典中的一个元素(从后往前删!)。
###4.4.字典应用案例
下面的代码首先生成包含1000个随机字符的字符串,然后统计每个字符的出现次数。
import string import random x=string.ascii_letters+string.digits+string.punctuation #字母+数字+标点字符串 x 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' y=[random.choice(x) for i in range(1000)] z=''.join(y) d=dict() for ch in z: d[ch]=d.get(ch,0)+1 # 也可以使用collections模块的defaultdict类来实现该功能 import string import random x=string.ascii_letters+string.digits+string.punctuation y=[random.choice(x) for i in range(1000)] z=''.join(y) from collections import defaultdict frequences=defaultdict(int) frequences defaultdict(<type 'int'>,{}) for item in z: frequences[item]+=1 frequences.items() # 使用collections模块的Counter类可以快速实现这个功能,并且能够满足其他需要,例如查找出现次数最多的元素。下面的代码演示了Counter类的用法: from collections import Counter frequences=Counter(z) frequences.items() dict_items([('v', 9), ('j', 13), ('x', 5), ('A', 8), ('c', 12), ('6', 11), ('>', 14), ('G', 10), ('m', 8), ('9', 11), ('Y', 15), ('~', 9), ('g', 11), ('2', 8), ('n', 6), ('L', 8), ('$', 11), ('7', 10), ('}', 7), ('e', 11), ('H', 10), ('4', 9), ('^', 13), ('h', 11), ('B', 15), ('|', 7), (';', 11), ('b', 12), ('d', 10), ('{', 11), ('V', 10), ('s', 13), ('@', 13), ('0', 14), ('#', 11), ('(', 12), ('P', 11), ('X', 10), ('t', 17), ('F', 7), ('5', 14), ('[', 14), ("'", 8), ('Q', 15), ('M', 17), ( '"', 4), (',', 12), ('w', 14), ('/', 15), ('?', 14), ('&', 9), ('\\', 11), ('f', 16), ('.', 13), ('o', 8), (']', 10), ('S', 9), ('1', 19), ('E', 11), (')', 10), ('U' , 15), ('Z', 12), ('=', 8), ('K', 8), ('u', 10), ('!', 10), ('I', 10), ('T', 11), ('y', 10), ('p', 15), ('8', 13), ('a', 11), ('3', 11), ('_', 9), ('D', 15), ('-', 5 ), ('C', 10), ('k', 4), ('l', 7), ('<', 11), (':', 14), ('+', 9), ('`', 9), ('z', 11), ('J', 7), ('r', 7), ('R', 9), ('q', 10), ('*', 6), ('i', 11), ('N', 6), ('O', 12), ('W', 11), ('%', 6)]) frequences.most_common(1) [('A',22)] frequences.most_common(3) [('A',22),(';',18),('`',17)] # 类似于列表推导式,Python也支持**字典推导式**快速生成符合特定条件的字典。 {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','b','d'] {i:j for i,j in zip(x,y)} {'A':'a','C':'b','B':'b','D':'d'}
1、这里说一下其中的random.choice()方法怎么用:random.choice(seq)
而random.choices语法格式:
random.choices(population, weights=None, *, cum_weights=None, k=1)
序列有多长,weights 对应的序列就得多长,每个位置都是一一对应
cum_weights=[1, 1, 1, 1, 1]
等价于 weights=[1, 0, 0, 0, 0]
[1,1+0,1+0+0,1+0+0+0,1+0+0+0+0]
2、join()函数方法
语法: ‘sep’.join(seq)
参数说明
sep:分隔符。可以为空
seq:要连接的元素序列、字符串、元组、字典
上面的语法即:以sep作为分隔符,将seq所有的元素合并成一个新的字符串
返回值:返回一个以分隔符sep连接各个元素后生成的字符串
3、而在上面中的字典对象的get()方法:可以获取指定“键”对应的值,并且可以在指定“键”不存在的时候返回指定值,如果不指定则默认返回None,且若无此“键”,则表示添加一个新的“键-值对”,也就是添加一个新元素。
4、defaultdict示例:
第一个参数提供default_factory
属性的初始值;它默认为None
. 所有剩余的参数都被视为与传递给dict
构造函数一样,包括关键字参数。
使用list
as default_factory
,很容易将一系列键值对分组到列表字典中:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
当第一次遇到每个键时,它还没有在映射中;default_factory
因此使用返回空的函数自动创建一个条目list
。然后该list.append()
操作将该值附加到新列表。当再次遇到键时,查找会正常进行(返回该键的列表)并且该 list.append()
操作将另一个值添加到列表中。
default_factory
将to设置为int
对 defaultdict
计数有用。
5、Counter用于计数,调用它会返回一个key为列表的值,value为该值的具体个数的对象。
most_common(n):用于显示前n个最多的元素。
Python内置字典是无序的,前面的示例很好地说明了这个问题。如果需要一个可以记住元素插入顺序的字典,可以使用collections.OrderedDict。
import collections
x=collections.OrderedDict() #有序字典
x['a']=3
x['b']=5
x['c']=8
x
OrderedDict([('a',3),('b',5),('c',8)])
集合是**无序可变序列,与字典一样使用一对大括号作为界定符**,同一个集合的元素之间不允许重复,集合中每个元素都是唯一的。
1、正如前面多次提到的,在Python中变量不需要提前声明其类型,直接将集合赋值给变量即可创建一个集合对象。
a={3,5}
a.add(7)
a
{3,5,7}
2、也可以使用set()*函数将列表、元组等其他可迭代对象转换为集合,如果原来的数据中存在重复元素,则在转换为集合的时候只保留一个。
a_set=set(range(8,14))
a_set
{8, 9, 10, 11, 12, 13}
b_set=set([1,2,3,4,5,6,7,8,9])
b_set
{1, 2, 3, 4, 5, 6, 7, 8, 9}
x=set() #空集合
3、可以使用集合对象的add()方法增加元素。当不再使用某个集合时,可以使用del命令删除整个集合。另外,也可以使用集合对象的pop()方法弹出并删除其中一个元素,或者使用集合对象的remove()方法直接删除指定元素,以及使用集合对象的clear()方法清空集合删除所有元素。
a={1,4,2,3} a.pop() 1 #弹出并删除 a {2,3,4} a.pop() 2 a {3,4} a.add(2) a {2,3,4} a.remove(3) #删除指定元素 a {2,4} a.pop(2) #pop方法不接收参数 TypeError:pop() takes no arguments
Python集合支持交集、并集、差集等运算:
a_set=set([8,9,10,11,12,13]) b_set=set([0,1,2,3,7,8]) a_set | b_set {0,1,2,3,7,8,9,10,11,12,13} #并集 a_set.union(b_set) #并集 {0,1,2,3,7,8,9,10,11,12,13} a_set & b_set #交集 {8} a_set.intersection(b_set) #交集 {8} a_set.difference(b_set) #差集 {9,10,11,12,13} a_set-b_set #差集 {9,10,11,12,13} a_set.symmetric_difference(b_set) #对称差 {0,1,2,3,7,9,10,11,12,13} a_set ^ b_set {0,1,2,3,7,9,10,11,12,13} #对称差 ----------------------------------------------- x={1,2,3} y={1,2,5} z={1,2,3,4} x<y #比较集合大小 False x<z True y<z False ----------------------------------------------- x.issubset(y) #测试是否为子集 False x.issubset(z) True
作为集合的具体应用,可以使用集合快速提取序列中单一元素,即提取出序列中所有不重复元素,如果使用传统方式,则需要编写下面的代码:
from random import randint
listRandom=[randint(0,9999) for i in range(100)] #100个介于0~9999之间的随机数
noRepeat=[]
for i in listRandom:
if i not in noRepeat:
noRepeat.append(i)
len(listRandom) #长度为100
len(noRepeat) #不重复元素的个数
如果使用集合,则只需要如下一行代码就可以了
newSet=set(listRandom)
Python集合的内部实现保证了元素不重复,并做了大量优化。
改变函数参数,增加不重复数的个数要求就会发现,序列越长,使用集合的效率越高。
最后,除了前面介绍的列表推导式、生成器推导式、字典推导式、Python也支持集合推导式。
{x.strip() for x in ('he','she ',' I')}
{'I','she','he'}
import random
x={random.randint(1,500) for i in range(100) #生成随机数,自动去除重复元素
len(x) #一般而言输出结果会小于100
列表对象提供了sort()方法支持原地排序,而内置函数sorted()返回新的列表,并不对原列表做任何修改。
除此之外,sorted()方法还可以对元组、字典排序,并且借助其key和cmp参数(Python3.x的sorted()方法没有cmp参数)可以实现更加复杂的排序。
persons=[{'name':'Dong','age':37},{'name':'Zhang','age':40},{'name':'Li','age':50},{'name':'Dong','age':43}] print(persons) [{'name':'Dong','age':37},{'name':'Zhang','age':40},{'name':'Li','age':50},{'name':'Dong','age':43}] # 使用key来指定排序依据,先按姓名升序排序,姓名相同的按年龄降序排序(-x降序,x升序) print(sorted(persons,key=lambda x:(x['name'],-x['age']))) [{'age':43,'name':'Dong'},{'age':37,'name':'Dong'},{'age":50,'name':'Li'},{'age':40,'name':'Zhang'}] # 使用operator模块的itemgetter(权值)函数对字典序列排序 from operator import itemgetter persons={'name':'Linda','age':43,'sex':'female'} sorted(persons.items(),key=itemgetter(0) [('age', 43), ('name', 'Linda'), ('sex', 'female')] #0为按字典中元素的键排序,1为按元素值排序 # 使用operator模块的itemgetter函数对列表中嵌套列表序列排序 gameresult=[['Bob',95.0,'A'],['Alan',86.4,'B'],['Mandy',83.4,'C'],['Mike',100,'S']] sorted(gameresult,key=itemgetter(0,1)) #按姓名升序,姓名相同的按分数升序排列 [['Alan', 86.4, 'B'], ['Bob', 95.0, 'A'], ['Mandy', 83.4, 'C'], ['Mike', 100, 'S']] sorted(gameresult,key=itemgetter(1,0)) #按分数升序,分数相同的按姓名升序排列 [['Mandy', 83.4, 'C'], ['Alan', 86.4, 'B'], ['Bob', 95.0, 'A'], ['Mike', 100, 'S']] sorted(gameresult,key=itemgetter(2,0)) #按等级升序,等级相同的按姓名升序排列 [['Bob', 95.0, 'A'], ['Alan', 86.4, 'B'], ['Mandy', 83.4, 'C'], ['Mike', 100, 'S']] # 同理: gameresult=[{'name':'Bob','wins':10,'losses':3,'rating':75.0}, {'name':'Alan','wins':3,'losses':5,'rating':57.0}, {'name':'David','wins':4,'losses':5,'rating':57.0}, {'name':'Patty','wins':9,'losses':3,'rating':72.8}] sorted(gameresult,key=itemgetter('wins','name')) #按wins升序,该值相同时按name升序排序 [{'name': 'Alan', 'wins': 3, 'losses': 5, 'rating': 57.0}, {'name': 'David', 'wins': 4, 'losses': 5, 'rating': 57.0}, {'name': 'Patty', 'wins': 9, 'losses': 3, 'rating': 72.8}, {'name': 'Bob', 'wins': 10, 'losses': 3, 'rating': 75.0}] # 以下代码演示如何根据另外一个列表的值来对当前列表元素排序 list1=["what","I'm","sorting","by"] list2=["something","else","to","sort"] pairs=zip(list1,list2) pairs=sorted(pairs) pairs [("I'm", 'else'), ('by', 'sort'), ('sorting', 'to'), ('what', 'something')] result=[x[1] for x in pairs] result ['else', 'sort', 'to', 'something']
在应用开发中,除了Python序列等基本数据类型之外,还经常需要使用到其他一些数据结构,例如堆、栈、队列、树、图等等。
堆在进行排序时使用较多,优先队列也是堆结构的一个重要应用。
堆是一个二叉树,其中每个父节点的值都小于或等于其所有子节点的值(小根堆)。
使用数组或列表来实现堆时,对于所有的k(下标,从0开始)都满足heap[k]<=heap[2*k+1]和heap[k]<=heap[2*k+2],并且整个堆中最小的元素总是位于二叉树的根节点(小根堆)。
Python在heapq模块中提供了对堆的支持。下面代码演示了堆的原理以及heapq模块的用法,同时也请注意random模块的用法。另外,当堆中没有元素时,进行heappop()操作会抛出异常。
import heapq import random data=list(range(10)) random.shuffle(data) #随机打乱列表中元素的顺序 data [4, 3, 0, 8, 5, 6, 7, 2, 1, 9] heap=[] for n in data: #建堆 heapq.heappush(heap,n) heap [0, 1, 3, 2, 5, 6, 7, 8, 4, 9] ------------------------------------------ heapq.heappush(heap,0.5) #新数据入堆 heap [0, 0.5, 3, 2, 1, 6, 7, 8, 4, 9, 5] ------------------------------------------- heapq.heappop(heap) #弹出最小的元素,堆会自动重建 0 heapq.heappop(heap) 0.5 heapq.heappop(heap) 1 ------------------------------------------- myheap=[1,2,3,5,7,8,9,4,10,333] heapq.heapify(myheap) #将列表转换为堆 myheap [1, 2, 3, 4, 7, 8, 9, 5, 10, 333] -------------------------------------------- heapq.heapreplace(myheap,6) #替换堆中的元素值,自动重新构建堆 1 myheap [2, 4, 3, 5, 7, 8, 9, 6, 10, 333] --------------------------------------------- heapq.nlargest(3,myheap) #返回前3个最大的元素 [333, 10, 9] heapq.nsmallest(3,myheap) #返回前3个最小的元素 [2, 3, 4]
队列的特点是**”先进先出FIFO“和”后进后出LILO“**,在多线程编程、作业处理等中有着重要作用。
Python提供了Queue模块(在Python3.x中为queue)和collections.deque模块支持队列的操作,当然也可以使用Python列表进行二次开发来实现自定义的队列结构。
>>> import queue
>>> q=queue.Queue()
>>> q.put(0) #元素入队,添加到队列尾部
>>> q.put(1)
>>> q.put(2)
>>> q.queue
deque([0, 1, 2])
>>> q.get() #队列头元素出队
0
>>> q.queue
deque([1, 2])
>>> q.get()
1
>>> q.queue
deque([2])
另外,Queue和queue模块还提供了”后进先出“队列和优先级队列
>>> import queue >>> LiFoQueue=queue.LifoQueue(5) #"后进先出"队列 >>> LiFoQueue.put(1) >>> LiFoQueue.put(2) >>> LiFoQueue.put(3) >>> LiFoQueue.get() 3 >>> LiFoQueue.get() 2 >>> LiFoQueue.get() 1 ------------------------------------- >>> import queue >>> PriQueue=queue.PriorityQueue(5) #优先级队列 >>> PriQueue.put(3) >>> PriQueue.put(5) >>> PriQueue.put(1) >>> PriQueue.put(8) >>> PriQueue.queue [1, 5, 3, 8] >>> PriQueue.get() 1 >>> PriQueue.get() 3 >>> PriQueue.get() 5 >>> PriQueue.get() 8
当然,我们还可以自定义队列结构,并且直接使用自定义队列类。
栈是一种**”后进先出LIFO“或”先进后出FILO“的数据结构**,Python列表本身就可以实现栈结构的基本操作。例如:列表对象的append()方法是在列表尾部追加元素,类似于入栈操作;pop()方法默认是弹出并返回列表的最后一个元素,类似于出栈操作。
但是直接使用Python列表对象模拟栈操作并不是很方便,例如,当列表为空时,若再执行pop()出栈操作,则会抛出一个不很友好的异常;另外也无法限制栈的大小。
myStack=[]
myStack.append(3)
myStack.append(5)
myStack.append(7)
myStack
[3,5,7]
myStack.pop()
7
myStack.pop()
5
myStack.pop()
3
myStack.pop()
IndexError:pop from empty list
当然也可以自定义栈结构,并且使用自定义栈。
可以直接使用Python列表及其基本操作来实现链表的功能,可以很方便地实现链表创建以及节点的插入和删除操作,当然也可以对列表进行封装来实现自定义的链表结构实现特殊功能或更加完美的外围检查工作。下面直接使用列表模拟链表及其基本操作:
linkTable=[]
linkTable.append(3) #在尾部追加节点
linkTable.append(5)
linkTable
[3,5]
linkTable.insert(1,4) #在链表中间插入节点
linkTable
[3,4,5]
linkTable.remove(linkTable[1]) #删除节点
linkTable
[3,5]
如前所述,使用列表直接模拟链表结构时,同样存在一些问题。
自定义二叉树结构:
class BinaryTree: def__init__(self,value): self.__left=None self.__right=None self.__data=value def insertLeftChild(self,value): #创建左子树 if self.__left: print('left child tree already exists.') else: self.__left=BinaryTree(value) return self.__left def insertRightChild(self,value): #创建右子树 if self.__right: print('right child tree already exists.') else: self.__right=BinaryTree(value) return self.__right def show(self): print(self.__data) def preOrder(self): #前序遍历 print(self.__data) if self.__left: self.__left.preOrder() #遍历左子树 if self.__right: self.__right.preOrder() #遍历右子树 def postOrder(self): #后序遍历 if self.__left: self.__left.postOrder() if self.__right: self.__right.postOrder() print(self.__data) def inOrder(self): #中序遍历 if self.__left: self.__left.inOrder() print(self.__data) if self.__right: self.__right.inOrder() if__name__=='__main__': print('Please use me as a module.')
把上面的代码保存为BinaryTree.py文件,下面代码创建了二叉树并对该树进行遍历。
import BinaryTree
root=BinaryTree.BinaryTree('root')
b=root.insertRightChild('B')
a=root.insertLeftChild('A')
c=a.insertLeftChild('C')
d=c.insertRightChild('D')
e=b.insertRightChild('E')
f=e.insertLeftChild('F')
root.inOrder()
C D A root B F E
root.postOrder()
D C A F E B root
b.inOrder()
B F E
自定义有向图结构,模拟有向图的创建和路径搜索功能。有向图由若干节点和边组成,其中每条边都是有明确方向的,即从一个节点指向另一个节点。若有向图中两个节点之间存在若干条有向边,则表示从起点可以到达终点,认为存在一条路径。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。