前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >盘一盘 Python 系列特别篇 - Collection

盘一盘 Python 系列特别篇 - Collection

作者头像
用户5753894
发布2020-04-10 15:13:14
5070
发布2020-04-10 15:13:14
举报
文章被收录于专栏:王的机器王的机器

引言

我们在【盘一盘 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) 是元组和字典的混合体,它赋予每个元素含义 (字典的特性),而且元素不可修改 (元组的特性)。

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

代码语言:javascript
复制
FP = namedtuple('FP', ['asset', 'instrument'])
FP
代码语言:javascript
复制
__main__.FP

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

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

代码语言:javascript
复制
product = FP('FX', 'European Option')
product
代码语言:javascript
复制
FP(asset='FX', instrument='European Option')

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

代码语言:javascript
复制
product._fields
代码语言:javascript
复制
('asset', 'instrument')
代码语言:javascript
复制
product.index('FX')
代码语言:javascript
复制
0
代码语言:javascript
复制
product.count('FX')
代码语言:javascript
复制
1

获取元素有三种方法:

  • 像元祖那样用数值索引
  • 像对象那样用点 .
  • 像对象那样用函数 getattr
代码语言:javascript
复制
print( product[0] )
print( product.asset )
print( getattr(product, 'asset') )
代码语言:javascript
复制
FX
FX
FX

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

代码语言:javascript
复制
product.asset = 'IR'

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

代码语言:javascript
复制
product = product._replace(asset='CM')
product
代码语言:javascript
复制
FP(asset='CM', instrument='European Option')

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

代码语言:javascript
复制
product1 = FP._make(['IR', 'Basis Swap'])
product1
代码语言:javascript
复制
FP(asset='IR', instrument='Basis Swap')

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

代码语言:javascript
复制
product2 = FP(**{'asset':'EQ', 'instrument':'Accumulator'})
product2
代码语言:javascript
复制
FP(asset='EQ', instrument='Accumulator')

2

defaultdict

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

代码语言:javascript
复制
issubclass(defaultdict, dict)
代码语言:javascript
复制
True

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

代码语言:javascript
复制
nums = defaultdict(int)  
nums['one'] = 1
nums['two'] = 2
nums['three'] = 3 
print( nums['four'] )
print( nums )
代码语言:javascript
复制
0
defaultdict(<class 'int'>, {'one': 1, 'two': 2, 'three': 3, 'four': 0})

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

再把类型设为 list 来举例。

代码语言:javascript
复制
def_dict = defaultdict(list)
def_dict['one'] = 1
def_dict['missing']
def_dict['another_missing'].append(4)
def_dict
代码语言:javascript
复制
defaultdict(list, {'one': 1, 'missing': [], 'another_missing': [4]})

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

3

Counter

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

代码语言:javascript
复制
issubclass(Counter, dict)
代码语言:javascript
复制
True

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

代码语言:javascript
复制
l = [1,2,3,4,1,2,6,7,3,8,1,2,2]  
answer = Counter(l)
print(answer)
print(answer[2])
代码语言:javascript
复制
Counter({2: 4, 1: 3, 3: 2, 4: 1, 6: 1, 7: 1, 8: 1})
4

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

4

deque

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

首先创建双端队列。

代码语言:javascript
复制
deq = deque([1, 10.31, 'Python'])  
print(deq)
代码语言:javascript
复制
deque([1, 10.31, 'Python'])

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

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

代码语言:javascript
复制
deq.append('OK')  
deq.appendleft(True)  
print(deq)
代码语言:javascript
复制
deque([True, 1, 10.31, 'Python', 'OK'])

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

代码语言:javascript
复制
deq.extend(['Go',0])  
deq.extendleft([None,'I'])  
print(deq)
代码语言:javascript
复制
deque(['I', None, True, 1, 10.31, 'Python', 'OK', 'Go', 0])

使用 pop 和 popleft 来删除元素。

代码语言:javascript
复制
p1 = deq.pop()  
p2 = deq.popleft()  
print(p1, p2)
print(deq)
代码语言:javascript
复制
0 I
deque([None, True, 1, 10.31, 'Python', 'OK', 'Go'])

5

ChainMap

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

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

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

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

代码语言:javascript
复制
inventory['Monopoly']
代码语言:javascript
复制
20

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

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

代码语言:javascript
复制
inventory.get('Super Mario')

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

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

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

代码语言:javascript
复制
toys['Nintendo'] = 200
inventory
代码语言:javascript
复制
ChainMap({'Monopoly': 20, 'Nintendo': 200}, 
         {'Mac': 1000, 'Lenovo': 800, 'Acer': 400}, 
         {'Jeans': 40, 'Tees': 10})

6

OrderedDict

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

代码语言:javascript
复制
issubclass(OrderedDict, dict)
代码语言:javascript
复制
True

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

代码语言:javascript
复制
order = OrderedDict()  
order['b'] = 1  
order['a'] = 2  
order['c'] = 3  
print(order)
代码语言:javascript
复制
OrderedDict([('b', 1), ('a', 2), ('c', 3)])
代码语言:javascript
复制
unordered = dict()
unordered['b'] = 1
unordered['a'] = 2
unordered['c'] = 3
print(unordered)
代码语言:javascript
复制
{'b': 1, 'a': 2, 'c': 3}

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

代码语言:javascript
复制
for key in order:
    print( key, ':', order[key] )
代码语言:javascript
复制
b : 1
a : 2
c : 3
代码语言:javascript
复制
for key in reversed(order):
    print( key, ':', order[key] )
代码语言:javascript
复制
c : 3
a : 2
b : 1

结果很直观,不解释了。

7

总结

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

Stay Tuned!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 王的机器 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档