python元组,集合,字典(4)

吉吉:

OC]

元组

  • 元组和列表类似,但属于不可变序列,元组一旦创建,用任何方法都不可以对其元素进行增删改的修改。
  • 元组的定义方式和列表相同,但定义时所有元素是放在一对圆括号“()”中,而不是方括号中。元组中的元素类型也可以不相同。

元组创建与删除

  • 使用“=”将一个元组赋值给变量

>>>a_tuple = ('a', 'b', 'mpilgrim', 'z', 'example')
>>> a_tuple
('a', 'b', 'mpilgrim', 'z', 'example')
>>> tup1 = ('中国', '美国', 1997, 2000)
>>> tup2 = (1, 2, 3, 4, 5 )
>>> tup3 = "a", "b", "c", "d"

>>> a = (3)
>>> a
3
>>> a = (3,) #包含唯一一个元素的元组,最后必须多写个逗号
>>> a
(3,)
>>> a = 3,  #也可以这样创建元组
>>> a
(3,)
>>> x = ()  #空元组,括号内为空

元组元素的读取和遍历

  • 和列表一样,用索引作为下标可以读取元组元素,若索引越界则抛出异常,注意引用下标的符号仍然是方括号[]。

- >>> x=(1,2,3)
>>> x[0]
1
>>> x[3]
Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
x[3]
IndexError: tuple index out of range #索引越界,抛出异常
>>> tup = (1, 2, 3, 4, 5, 6, 7 )
>>> print (“tup [1:5]: ”, tup [1:5])  # 对元组切片,输出第二个元素开始到第五个元素
tup [1:5]:  (2, 3, 4, 5)
  • 可以使用for循环来遍历元组中的所有元素

>>> for i in x: 
  print(i)
1
2
3

元组与列表的区别

  • 元组中的元素一旦定义就不允许更改。

>>> x=(1,2,3)
>>> x[0]
1
>>> x[0]=4
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
x[0]=4
TypeError: 'tuple' object does not support item assignment
  • 元组没有append()、extend()和insert()等方法,无法向元组中添加元素。元组没有remove()或pop()方法,也无法对元组元素进行del操作,不能从元组中删除元素。
  • 从效果上看,tuple( )冻结列表,而list( )融化元组。

元组连接

  • 元组中的元素值是不允许修改的,但可以对元组进行连接运算,生成一个新的元组。

>>> tup1 = (12, 34,56)
>>> tup2 = (78, 90)
>>> tup3 = tup1 + tup2   #连接元组,创建一个新的元组
>>> tup3
(12, 34, 56, 78, 90)
  • 元组的优点

  • 元组的速度比列表更快。如果定义了一系列常量值,而所需做的仅是对它进行遍历,那么一般使用元组而不用列表。
  • 元组对不需要改变的数据进行“写保护”将使得代码更加安全。
  • 元组可用作字典键(特别是包含字符串、数值和其它元组这样的不可变数据的元组)。列表永远不能当做字典键使用,因为列表不是不可变的。

生成器推导式

  • 生成器推导式的结果是一个生成器对象。使用生成器对象的元素时,可以根据需要将其转化为列表或元组,也可以使用生成器对象__next__()方法或内置函数next()进行遍历,或者直接将其作为迭代器对象来使用。
  • 生成器对象具有惰性求值的特点,只在需要时生成新元素,比列表推导式具有更高的效率,空间占用非常少,尤其适合大数据处理的场合。
  • 不管用哪种方法访问生成器对象,都无法再次访问已访问过的元素。
  • 使用生成器对象__next__()方法或内置函数next()进行遍历

>>> g = ((i+2)**2 for i in range(10)) #创建生成器对象
>>> g
<generator object <genexpr> at 0x0000000003095200>
>>> tuple(g) #将生成器对象转换为元组
(4, 9, 16, 25, 36, 49, 64, 81, 100, 121)
>>> list(g) #生成器对象已遍历结束,没有元素了
[] 
>>> g = ((i+2)**2 for i in range(10))  #重新创建生成器对象
>>> g.__next__() #使用生成器对象的__next__()方法获取元素
4
>>> g.__next__() #获取下一个元素
9
>>> next(g)  #使用函数next()获取生成器对象中的元素
16
  • 使用for循环直接遍历生成器对象中的元素

>>> g = ((i+2)**2 for i in range(10))
>>> for item in g:#使用循环直接遍历生成器对象中的元素
   print(item, end=' ')
4 9 16 25 36 49 64 81 100 121 
>>> x = filter(None, range(20))   #filter对象也具有类似的特点
>>> 5 in x
True
>>> 2 in x#不可再次访问已访问过的元素
False
>>> x = map(str, range(20))   #map对象也具有类似的特点
>>> '0' in x
True
>>> '0' in x   #不可再次访问已访问过的元素
False
  • 内置函数map()把一个函数func依次映射到序列或迭代器对象的每个元素上,并返回一个可迭代的map对象作为结果,map对象中每个元素是原序列中元素经过函数func处理后的结果。

>>> list(map(str, range(5)))#把列表中元素转换为字符串
['0', '1', '2', '3', '4']
>>> def add5(v):#单参数函数
	return v+5
>>> list(map(add5, range(10)))  #把单参数函数映射到一个序列的所有元素
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> def add(x, y):#可以接收2个参数的函数
	return x+y
>>> list(map(add, range(5), range(5,10)))  #把双参数函数映射到两个序列上
[5, 7, 9, 11, 13]
  • 内置函数filter()将一个单参数函数作用到一个序列上,返回该序列中使得该函数返回值为True的那些元素组成的filter对象,如果指定函数为None,则返回序列中等价于True的元素。

>>> seq = ['foo', 'x41', '?!', '***']
>>> def func(x):
	return x.isalnum() #测试是否为字母或数字
>>> filter(func, seq)#返回filter对象
<filter object at 0x000000000305D898>
>>> list(filter(func, seq))  #把filter对象转换为列表
['foo', 'x41']

字典

  • 字典是一个由键和值组成的键—值对构成的集合,每一个字典元素分为两部份:键(key)和值(value)。每个键都与一个值相关联,可以使用键来访问与之相关联的值。
  • 字典是无序可变序列。
  • 定义字典时,每个元素的键和值用冒号分隔,元素之间用逗号分隔,所有的元素放在一对大括号“{}”中。
  • 字典中的键可以为任意不可变数据,比如整数、实数、复数、字符串、元组等等。注意,列表可变不能当键。与键相关联的值可以是数字、字符串、列表乃至字典等任意对象。
  • globals()返回包含当前作用域内所有全局变量和值的字典
  • locals()返回包含当前作用域内所有局部变量和值的字典

字典创建与删除

  • 使用=将一个字典赋值给一个变量

>>> a_dict = {'server': 'db.diveintopython3.org', 'database': 'mysql'}
>>> a_dict
{'database': 'mysql', 'server': 'db.diveintopython3.org'}
>>>d1={1:'MON',2:'TUE',3:'WED',4:'THU',5:'FRI',6:'SAT',0:'SUN'}
>>> d1
{0: 'SUN', 1: 'MON', 2: 'TUE', 3: 'WED', 4: 'THU', 5: 'FRI', 6: 'SAT'}

>>> x = {} #空字典
>>> x
{}
  • 使用dict()函数利用已有数据创建字典:

>>> keys = ['a', 'b', 'c', 'd']
>>> values = [1, 2, 3, 4]
>>> dictionary = dict(zip(keys, values))
>>> dictionary
{'a': 1, 'c': 3, 'b': 2, 'd': 4}
>>> x = dict()   #空字典
>>> x
{}
  • 使用dict()根据给定的键、值创建字典

>>> d = dict(name=‘Zou', age=40)
>>> d
{'age': 40, 'name': ‘Zou'}
  • 用字典的fromkeys方法以给定内容为键,创建值为空值None的字典。

>>> adict = dict.fromkeys(['name', 'age', 'sex'])
>>> adict 
{'age': None, 'name': None, 'sex': None}
  • 可以使用del删除整个字典

字典元素的读取引用

  • 以键作为下标用[]引用,可以读取指定键值对应的值,若键不存在则抛出异常

>>> aDict = {'name':'Zou', 'sex':'female', 'age':40}
>>> aDict['name']
'Zou'
>>> aDict['tel'] #键不存在,抛出异常
Traceback (most recent call last):
  File "<pyshell#53>", line 1, in <module>
aDict['tel']
Key Error: 'tel'

  • 为避免引用时抛出异常,更推荐使用字典对象的get方法获取指定键对应的值,并且可以在键不存在的时候返回指定默认值。

>>> print(aDict.get('address'))
None
>>> print(aDict.get(‘address’, ‘HBUE’))#键值不存在则返回指定值
HBUE

  • 使用字典对象的items()方法可以返回以字典的键值对元组为元素的可迭代对象。此方法比较常用。
  • 使用字典对象的keys()方法可以返回字典的键”列表”。
  • 使用字典对象的values()方法可以返回字典的值”列表”。

>>> aDict = {'name':'Zou', 'sex':'female', 'age':40}

>>> aDict.items()
dict_items([('age', 40), ('name', 'Zou'), ('sex', 'female')])
  #返回所有键值对
>>> aDict.keys()#返回所有键
dict_keys(['name', 'sex', 'age'])

>>> aDict.values()  #返回所有值
dict_values([‘Zou', ‘female', 40])
  • 这些方法返回的值不是真正的列表,它们不能被修改,没有append()方法。但这些数据类型可以用于for循环。(重点)

字典元素的遍历

  • 字典也是可迭代对象,也可以使用for循环来遍历字典元素

>>> aDict={'name':'Zou', 'sex':'female', 'age':40}
>>> for key in aDict:  #字典循环时不加特殊说明,默认对键迭代
	print(key)
age
name
sex
>>> for item in aDict.items():#输出字典中所有键值对元组	   print(item)
('age', 40)
('name', 'Zou')
('sex', ‘female')
>>> for key, value in aDict.items():  #序列解包用法
	   print(key, value)
age 40
name Zou
sex female

字典元素的添加与修改

  • 当以指定键为下标为字典元素赋值时,若键存在,则可以修改该键的值;若不存在,则表示添加一个键值对元素。

>>> aDict['age'] = 41  #修改元素值
>>> aDict
{'age': 41, 'name': ‘Zou', 'sex': ‘female'}
>>> aDict['address'] = 'HBUE'   #增加新的键值对元素
>>> aDict
{'age': 41, 'address': ‘HBUE', 'name': ‘Zou', 'sex': ‘female'}
>>> aDict['score'] = aDict.get('score',[])  #若’score’键存在返回其值否则返回空列表
>>> aDict['score'].append(98)
>>> aDict['score'].append(97)
>>> aDict
{'age': 41, 'score': [98, 97], 'name': ‘Zou', 'sex': ‘female'}
  • 使用字典对象的update方法将另一个字典的键、值对添加到当前字典对象

>>> adict={'age': 40, 'score': [98, 97], 'name': 'Zou', 'sex': 'female'}
>>> adict.update({'a':'a', 'b':'b', 'age':41})
>>> adict
{'age': 41, 'score': [98, 97], 'name': 'Zou', 'sex': 'female', 'a': 'a', 'b': 'b'}
  • 使用del删除字典中指定键的元素
  • 使用字典对象的clear()方法来删除字典中所有元素
  • 使用字典对象的pop()方法删除并返回指定键的元素
  • 使用字典对象的popitem()方法删除并返回字典中的一个元素

字典应用案例

  • 首先生成包含1000个随机字符的字符串,然后统计每个字符的出现次数。

>>> import string
>>> import random
>>> x = string.ascii_letters + string.digits + string.punctuation
>>> 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()
#defaultdict接受一个工厂函数作为参数,这个factory_function可以是list、set、str等等,作用是当key不存在时,返回的是工厂函数的默认值,比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0

所谓工厂函数,就是指这些内建函数都是类对象,当你调用他们时,实际上是创建了一个类实例”。意思就是当我调用这个函数,实际上是先利用类创建了一个对象,然后返回这个对象。

  • 对于频次统计的问题,使用collections模块的Counter类可以更加快速地实现这个功能,并且能够提供更多的功能,例如查找出现次数最多的元素。

>>> from collections import Counter
>>> frequences = Counter(z)
>>> frequences.items()
>>> frequences.most_common(1) #出现次数最多的一个字符
[('A', 22)]
>>> frequences.most_common(3)
[('A', 22), (';', 18), ('`', 17)]

有序字典

  • Python内置字典是无序的,如果需要一个可以记住元素插入顺序的字典,可以使用collections.OrderedDict。

>>> x = dict()   #无序字典
>>> x['a'] = 3
>>> x['b'] = 5
>>> x['c'] = 8
>>> x
{'b': 5, 'c': 8, 'a': 3}
>>> import collections
>>> x = collections.OrderedDict() #有序字典
>>> x['a'] = 3
>>> x['b'] = 5
>>> x['c'] = 8
>>> x
OrderedDict([(‘a’, 3), (‘b’, 5), (‘c’, 8)])
#展示有序字典OrderedDict对象的值

字典推导式


>>> s = {x:x.strip() for x in ('  he  ', 'she', 'I')}
>>> s
{'  he  ': 'he', 'I': 'I', 'she': 'she'}
>>> for k, v in s.items():
	   print(k, ':', v)

  he   : he
I : I
she : she 
>>> {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'}

集合

  • 集合是无序可变序列,使用一对大括号{}界定。

  • 集合是无序的,不能通过数字进行索引。

  • 元素不可重复,同一个集合中每个元素都是唯一的。

  • 集合基本功能是进行成员关系测试和删除重复元素。

集合的创建与删除

  • 直接将集合赋值给变量

>>> a = {3, 5}
>>> {1,2,3}
{1, 2, 3}
>>> {(1,2),3}
{(1, 2), 3}
>>> {[1,2],3}
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
{[1,2],3}
TypeError: unhashable type: 'list'

集合中只能包含数字、字符串、元组等不可变类型(或者说可哈希)的数据,而不能包含列表、字典、集合等可变类型的数据。

  • 使用set函数将其他序列数据转换为集合

>>> a_set = set(range(8,14))
>>> a_set
{8, 9, 10, 11, 12, 13}
>>> b_set = set([0, 1, 2, 3, 0, 1, 2, 3, 7, 8])  #自动去除重复
>>> b_set
{0, 1, 2, 3, 7, 8}
>>> c_set = set()  #空集合
>>> c_set
set()
  • 创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
  • 当不再使用某个集合时,可以使用del命令删除整个集合。

集合元素的创建与删除

因为集合可变,所以集合对象支持add()方法增加元素,pop()方法弹出(删除)并返回其中一个元素,remove()方法直接删除指定元素,clear()方法清空集合。


>>> a = {1, 4, 2, 3}
>>> a.pop() 
1 #集合是无序的,故可能弹出任意一个元素
>>> a.pop()
2
>>> a
{3, 4}
>>> a.add(2)#如果集合里原来就包含2,则忽略
>>> a
{2, 3, 4}
>>> a.remove(3)
>>> a
{2, 4}
>>> a.clear()
>>> a
set()

集合操作

  • Python集合支持交集、并集、差集等运算(位运算符和集合对象方法两种实现方式)

>>> a_set = set([8, 9, 10, 11, 12, 13])
>>> b_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 - b_set #差集
{9, 10, 11, 12, 13}
>>> a_set.difference(b_set) #差集
{9, 10, 11, 12, 13}
>>> a_set = {8,9, 10, 11, 12, 13}
>>> b_set = {0, 1, 2, 3, 7, 8}
>>> 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}
>>> {1,3}.isdisjoint({2,4,5})#测试是否无交集,如果两个集合的交集为空返回True
True
>>> x.issubset(y)  #测试是否为子集
False
>>> x.issubset(z)
True
>>> x < y#比较集合大小/包含关系
False
>>> x < z #真子集
True
>>> y < z
False
>>> {1, 2, 3} <= {1, 2, 3}#子集
True 
  • 注意:不同于关系运算,not(x<y)不等价x>=y
  • 可以使用集合快速提取序列中单一元素,即提取出序列中所有不重复元素。
  • 如果使用传统方式的话,需要编写下面的代码:

>>> import random
>>> listRandom = [random.choice(range(10000)) for i in range(100)]
#生成包含100个数的列表,每个数都是0~999的整数
>>> noRepeat = []
>>> for i in listRandom :
	  if i not in noRepeat :
		 noRepeat.append(i)
>>> len(listRandom)
>>> len(noRepeat)

- 而如果使用集合的话,只需要下面这么一行代码就可以了。

----------
>>> newSet = set(listRandom) #直接去掉重复值
  • 注意:random.choice(seq)用于返回一个列表,元组或字符串seq的随机项。
  • 集合运用案例
  • 生成不重复随机数的效率比较。

import random
import time

def RandomNumbers(number, start, end):
'''使用列表来生成number个介于start和end之间的不重复随机数'''
data = []
n = 0
while True:
element = random.randint(start, end)
if element not in data:
data.append(element)
n += 1
if n == number :
break
return data

> 注意:random.randint(a,b)用于生成一个指定范围内的整数。其中参数a是下限,参数b是上限,生成的随机数n: a <= n <= b。
def RandomNumbers1(number, start, end):
'''使用列表来生成number个介于start和end之间的不重复随机数,'''
data = []#此算法省略计数器n
while True:
element = random.randint(start, end)
if element not in data:
data.append(element)
if len(data) == number:  #用len()函数测试列表长度
break
return data
def RandomNumbers2(number, start, end):
'''使用集合来生成number个介于start和end之间的不重复随机数'''
data = set()
while True:
data.add(random.randint(start, end))   
#运用集合的add()方法,自动忽略重复元素
if len(data) == number:
break
return data
start = time.time()
for i in range(10000):
RandomNumbers(1000, 1, 10000)
print('Time used:', time.time()-start)

start = time.time()
for i in range(10000):
RandomNumbers1(1000, 1, 10000)
print('Time used:', time.time()-start)

start = time.time()
for i in range(10000):
RandomNumbers2(1000, 1, 10000)
print('Time used:', time.time()-start)

集合推导式


>>> s = {x.strip() for x in ('  he  ', 'she', 'I')}
>>> s
{'I', 'she', 'he'}

序列解包*

  • 序列解包的本质就是把一个序列或可迭代对象中的元素同时赋值给多个变量,如果等号右侧含有表达式,会把所有表达式的值先计算出来,然后再进行赋值。可以使用序列解包功能对多个变量同时赋值

>>> x, y, z = 1, 2, 3  #多个变量同时赋值
>>> v_tuple = (False, 3.5, 'exp')
>>> (x, y, z) = v_tuple
>>> x, y, z = v_tuple
>>> x, y, z = [1, 2, 3]  #使用可迭代对象列表进行序列解包
>>> x, y, z = sorted([1, 3, 2]) #sorted()函数返回排序后的列表
>>> a, b, c = 'ABC'#字符串也支持序列解包
>>> x, y, z = range(3)   #可以对range对象进行序列解包 
>>> x, y, z = map(str, range(3))#使用可迭代的map对象进行序列解包
>>> x = [1, 2, 3, 4, 5, 6]
>>> x[:3] = map(str, range(5))#切片也支持序列解包
>>> x
['0', '1', '2', '3', '4', 4, 5, 6]

>>> a, b = b, a  #交换两个变量的值
  • 下面的代码用来生成斐波那契数列中小于100的数字:
    def fib(n):

a, b = 1, 1#序列解包赋值
while a < n:
print(a, end=' ')
a, b = b, a+b #序列解包赋值

fib(100)
  • 序列解包对于字典同样有效

>>> s = {'a':1, 'b':2, 'c':3}
>>> b, c, d = s  #使用字典时不用太多考虑元素的顺序
>>> b
'c'
>>> b, c, d = s.values()
>>> print(b, c, d)
1 3 2
>>> b, c, d = s.items()
>>> b
('c', 3)
  • 使用序列解包遍历zip对象

>>> 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) 
>>> 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}}
{'y': 2, 'x': 1}
  • 序列解包的一种简单用法就是把首个或前几个元素与后面几个元素分别提取出来,例如:

first, seconde, *rest = sequence
  • 如果sequence里至少有三个元素,那么执行完上述代码后,

first == sequence[0], second == sequence[0], rest == sequence[2:]
发布了44 篇原创文章 · 获赞 82 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/weixin_41503009/article/details/85640900