社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

盘一盘 Python 系列特别篇 - Collection

王的机器 • 4 年前 • 316 次点击  




本文含 4818 6 图表截屏
建议阅读 26 分钟



本文是 Python 系列的特别篇的第十二篇




0
引言


我们在盘一盘 Python 下】一贴介绍过 5 种类型的容器型(container)数据,分别是字符串(string)、列表(list)、元组(tuple)、字典(dictionary)和集合(set)。


顾名思义,容器型就是将一组元素打包在一起。有人觉得字符串不是容器型数据,但我认为它将一个个字符(character)打包在一起,因此也算是容器型数据。


今天我们来介绍除上面 5 个之外的容器型数据,统称 Collection,见下图。



上图中的 UserDict, UserList 和 UserString 只是字典、列表和字符串的一个简单封装,而 frozenset 就是“元素不可修改”的集合,它们平时使用的频率很少,因此略过不讲。


本帖只介绍 6 种使用较多(和上面 4 种较少的相比而言)的 Collection,它们是


  1. namedtuple

  2. defaultdict

  3. Counter

  4. deque

  5. ChainMap

  6. OrderedDict


再具体讲它们之前,我们来思考一个基础问题,为什么要创造它们?字符串列表元组字典集合这“五大金刚”不香吗?创造它们一定是五大金刚有缺陷,先看看它们之间的功能总结。



请思考:


  • 元组的可读性太差但不可修改,字典的可读性强但可修改,两者一结合便是命名元组 (namedtuple)。


  • 在读写字典时,如果键不存在会报错,那么就有了默认字典 (defaultdict)。


  • 计数器 (Counter) 是个字典的子类,能快速计量元素出现的个数。


  • 列表只能从尾部添加元素,不能从头部,那么就有了双端队列 (deque)。


  • 在多个字典上操作效率不高,那么就有了链式映射 (ChainMap)。


  • 原来普通字典在读取中不能记录放入元素的顺序(现在可以了),那么就有了有序字典 (OrderedDict)。因此我觉得有序字典现在用处不大,但还是讲讲吧。



你看带着这种思路学习新知识,是不是目的性更强一些,也更容易记住知识点。





1
namedtuple


命名元组 (namedtuple) 是元组和字典的混合体,它赋予每个元素含义 (字典的特性),而且元素不可修改 (元组的特性)。


创建命名元组需要设定两个必需参数:元组名称字段名称

FP = namedtuple('FP', ['asset', 'instrument'])FP
__main__.FP


其中 FP 是 Financial Product 的缩写,我们发现 namedtuple 创建的和类 (class) 很像。


有了“类”,我们可以创建“对象”了,来试试创建一个外汇欧式期权(FX European Option),语法如下:

product = FP('FX', 'European Option')product
FP(asset='FX', instrument='European Option')


像字典一样查看其键 (用 _fields),像元组一样查看其值的索引 (用 index) 和计数 (用 count)。


product._fields
('asset', 'instrument')
product.index('FX')
0
product.count('FX')
1


获取元素有三种方法:


  • 像元祖那样用数值索引

  • 像对象那样用点 .

  • 像对象那样用函数 getattr


print( product[0] )print( product.asset )print( getattr(product, 'asset') )



    
FX
FX
FX


元组不可修改,命名元组也是,应该直接更新其元素会报错。

product.asset = 'IR'


但可以用 _replace 函数更新其值,并生成新的命名元组,比如把资产类别从外汇 FX 换到商品 CM。

product = product._replace(asset='CM')product
FP(asset='CM', instrument='European Option')


用 _make 函数创建新的命名元组

product1 = FP._make(['IR', 'Basis Swap'])product1
FP(asset='IR', instrument='Basis Swap')


还可以用字典打散的形式来创建命名元组

product2 = FP(**{'asset':'EQ', 'instrument':'Accumulator'})product2
FP(asset='EQ', instrument='Accumulator')





2
defaultdict


默认字典 (defaultdict) 和字典不同,我们不需要检查键是否存在,对于不存在的键,会赋一个默认值。


issubclass(defaultdict, dict)
True



创建默认字典时候记住要先设定好其值类型,用 int 举例先。

nums = defaultdict(int)  nums['one'] = 1nums['two'


    
] = 2nums['three'] = 3 print( nums['four'] )print( nums )
0
defaultdict(<class 'int'>, {'one': 1, 'two': 2, 'three': 3, 'four': 0})


你看,字典 nums 没有 'four' 这个键,因此给它赋予整型变量的默认值 0,如果是浮点型变量,那么默认值是 0.0,如果是字符串,那么默认值是 ''。



再把类型设为 list 来举例。

def_dict = defaultdict(list)def_dict['one'] = 1def_dict['missing']def_dict['another_missing'].append(4)def_dict
defaultdict(list, {'one': 1, 'missing': [], 'another_missing': [4]})


当键为 'missing' 和 'another_missing' 时,空列表 [] 作为默认值赋给其键对应的值。





3
Counter


计数器 (Counter) 是字典的子类,提供了可哈希(hashable)对象的计数功能。可哈希就是可修改(mutable),比如列表就是可哈希或可修改。


issubclass(Counter, dict)
True



一个简单例子来看 Counter 怎么使用。

l = [1,2,3,4,1,2,6,7,3,8,1,2,2]  answer = Counter(l)print(answer)print(answer[2])
Counter({2: 4, 1: 3, 3: 2, 4: 1, 6: 1, 7: 1, 8: 1})
4


结果很直观,不用解释了。





4
deque


双端队列 (deque) 可让我们从头/尾两端添加或删除元素。


首先创建双端队列。

deq = deque([1, 10.31, 'Python'])  print(deq)
deque([1, 10.31, 'Python'])


我们知道列表里用 append,extendpop 方法,它们只能从尾部添加或删除元素,那么在双端队列里有 appendleft, extendleftpopleft 方法,从左边,即尾部,添加或删除元素。看例子。


使用 append 和 appendleft,把参数来整块添加。

deq.append('OK')  deq.appendleft(True)  print(deq)
deque([True, 1, 10.31, 'Python', 'OK'])



使用 extend  extendleft 把参数来打散添加,列表 ['Go', 0] 打散成两个元素添加上去,如果是 append 那么就把这个列表当成整体添加上去。

deq.extend(['Go',0])  deq.extendleft([None,'I'])  print(deq)
deque(['I', None, True, 1, 10.31, 'Python', 'OK', 'Go', 0])



使用 poppopleft 来删除元素。

p1 = deq.pop()  p2 = deq.popleft()  print(p1, p2)print(deq)
0 I
deque([None, True, 1, 10.31, 'Python', 'OK', 'Go'])





5
ChainMap


链式映射 (ChainMap) 可看成字典的容器,将多个映射串联起来,这样它们就可以作为一个单元处理。通常比创建一个新字典和多次调用 update 函数要快很多。


首先创建链式映射,先创建三个字典,再把它们打包成 ChainMap

toys = {'San Guo Sha': 30, 'Monopoly': 20}computers = {'Mac': 1000, 'Lenovo': 800, 'Acer': 400}clothing = {'Jeans': 40, 'Tees': 10}
inventory = ChainMap( toys, computers, clothing )inventory
ChainMap({'San Guo Sha': 30, 'Monopoly': 20},
         {'Mac': 1000, 'Lenovo': 800, 'Acer': 400},
         {'Jeans': 40, 'Tees': 10})



查看键大富豪, 'Monopoly' 对应的值。

inventory['Monopoly']
20

如果多个字典都有某个键,那么返回第一个含该键的字典的值。



get() 函数查看超级玛丽,'Super Mario',如果每个字典都没此键,不返回值也不报错。

inventory.get('Super Mario')


删除三国杀, 'San Guo Sha'。

p = inventory.pop('San Guo Sha')print(p)inventory
30
ChainMap({'Monopoly': 20},
         {'Mac': 1000 , 'Lenovo': 800, 'Acer': 400},
         {'Jeans': 40, 'Tees': 10})



在 Toy 字典中添加任天堂,'Nintendo'。

toys['Nintendo'] = 200inventory
ChainMap({'Monopoly': 20, 'Nintendo': 200}, 
         {'Mac': 1000, 'Lenovo': 800, 'Acer': 400},
         {'Jeans': 40, 'Tees': 10})





6
OrderedDict


有序字典 (OrderedDict是字典的子类,就像常规字典一样,它会记录放入元素的顺序,但现在常规字典也有这种功能了,因此有序字典的存在意义也不大了。


issubclass(OrderedDict, dict)
True



首先创建有序词典和常规字典,发现两者都是按着元素放入的顺序来记录的。

order = OrderedDict()  order['b'] = 1  order['a'] = 2  order['c'] = 3  print(order)



    
OrderedDict([('b', 1), ('a', 2), ('c', 3)])


unordered = dict()unordered['b'] = 1unordered['a'] = 2unordered['c'] = 3print(unordered)
{'b': 1, 'a': 2, 'c': 3}



有序词典中,有一个 reversed() 函数,可以逆序返回字典的键。对比下面两个例子。

for key in order:    print( key, ':', order[key] )
b : 1
a : 2
c : 3


for key in reversed(order):    print( key, ':', order[key] )
c : 3
a : 2
b : 1


结果很直观,不解释了。





7
总结


就一张图,看那些连点的细节,不解释。




Stay Tuned!


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/61189
 
316 次点击