前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 字典 dict

Python 字典 dict

作者头像
为为为什么
发布2022-08-09 18:05:46
7910
发布2022-08-09 18:05:46
举报
文章被收录于专栏:又见苍岚

Python 字典提供了散列查询的功能,使用灵活效率高,本文记录相关内容。

定义方式

字典是一种可变容器模型,且可存储任意类型对象

  • 核心目的是要为每对记录提供 key 和 value,key 一定要可哈希的对象
代码语言:javascript
复制
a = dict(one=1, two=2, three=3)
b = {'one': 1, 'two': 2, 'three': 3}
c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
d = dict([('two', 2), ('one', 1), ('three', 3)])
e = dict({'three': 3, 'one': 1, 'two': 2})

-->
a == b == c == d == e
True

字典推导

代码语言:javascript
复制
DIAL_CODES = [
 (86, 'China'), 
 (91, 'India'), 
 (1, 'United States'), 
 (62, 'Indonesia'), 
 (55, 'Brazil'), 
 (92, 'Pakistan'), 
 (880, 'Bangladesh'), 
 (234, 'Nigeria'), 
 (7, 'Russia'), 
 (81, 'Japan'), 
 ] 
 
 country_code = {country: code for code, country in DIAL_CODES}
 print(country_code)
 >>>
{'China': 86, 'India': 91, 'United States': 1, 'Indonesia': 62, 'Brazil': 55, 'Pakistan': 92, 'Bangladesh': 880, 'Nigeria': 234, 'Russia': 7, 'Japan': 81}
 <<<
 
 print({code: country.upper() for country, code in country_code.items() if code < 66})
 >>>
 {1: 'UNITED STATES', 62: 'INDONESIA', 55: 'BRAZIL', 7: 'RUSSIA'}
 <<<

常见的映射方法

  • 映射类型的方法其实很丰富,常用的有 dict、defaultdict 和 OrderedDict 的常见方法,后面两个数据类型 是 dict 的变种,位于 collections 模块内。
  • dict、collections.defaultdict和 collections.OrderedDict这三种映射类型的方法列表:

setdefault 方法可以作为创建字典键值对的简化方法

代码语言:javascript
复制
my_dict.setdefault(key, []).append(new_value)

等价于

代码语言:javascript
复制
if key not in my_dict: 
	my_dict[key] = [] 
my_dict[key].append(new_value)

映射的弹性键查询

有时候为了方便起见,就算某个键在映射里不存在,我们也希望在通过 这个键读取值的时候能得到一个默认值。有两个途径能帮我们达到这个目的,一个是通过 defaultdict,这个类型而不是普通的 dict,另一个 是给自己定义一个 dict 的子类,然后在子类中实现 __missing__ 方法。

defaultdict
  • 建立对象时接受可调用的对象作为参数送入 default_factory,当查找值不在字典中时调用对象创建对象填入字典
代码语言:javascript
复制
from collections import defaultdict

d = defaultdict(lambda: 'abc')
print(d['a'])
print(d)


-->
abc
defaultdict(<function <lambda> at 0x000001E57743BA60>, {'a': 'abc'})

  • 当需要为不存在的键值创建空列表对象时,可以:
代码语言:javascript
复制
from collections import defaultdict

index = defaultdict(list)
index['word'].append('abc')
print(index)


-->
defaultdict(<class 'list'>, {'word': ['abc']})

  • 如果在创建 defaultdict 的时候没有指定 default_factory,查询不 存在的键会触发 KeyError。
  • defaultdict 里的 default_factory 只会在 __getitem__ 里被调用,在其他的方法里完全不会发挥作用。比 如,dd 是个 defaultdict,k 是个找不到的键, dd[k] 这个表达 式会调用 default_factory 创造某个默认值,而 dd.get(k) 则会 返回 None。 所有这一切背后的功臣其实是特殊方法 __missing__。它会在 defaultdict 遇到找不到的键的时候调用 default_factory,而实际 上这个特性是所有映射类型都可以选择去支持的。
__missing__

所有的映射类型在处理找不到的键的时候,都会牵扯到 __missing__ 方法。这也是这个方法称作“missing”的原因。虽然基类 dict 并没有定 义这个方法,但是 dict 是知道有这么个东西存在的。也就是说,如果 有一个类继承了 dict,然后这个继承类提供了 __missing__ 方法,那 么在 __getitem__ 碰到找不到的键的时候,Python 就会自动调用它, 而不是抛出一个 KeyError 异常。

  • __missing__ 方法只会被 __getitem__ 调用(比如在表达 式 d[k] 中)。提供 __missing__ 方法对 get 或者 __contains__(in 运算符会用到这个方法)这些方法的使用没有 影响。
代码语言:javascript
复制
class StrKeyDict0(dict):
    def __missing__(self, key): 
        if isinstance(key, str):
            raise KeyError(key) 
        return self[str(key)]
    
    def get(self, key, default=None):
        try:
            return self[key]
        except KeyError: 
            return default
    
    def __contains__(self, key):
        return key in self.keys() or str(key) in self.keys()

d = StrKeyDict0([('2', 'two'), ('4', 'four')])
print(d['2'])
print(d[2])


-->
two
two

定义了 __missing__ 方法,在查不到值时转换为 str 重新查询

字典的变种

标准库里 collections 模块中,除了 defaultdict 之外还有其他的映射类型。

collections.OrderedDict

这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致 的。OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素,但是如果像 my_odict.popitem(last=False) 这样调用 它,那么它删除并返回第一个被添加进去的元素。

collections.ChainMap

该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止。这个功能在给有嵌套作用域的语言做解释器的时候很有用,可以用一个映射 对象来代表一个作用域的上下文。在 collections 文档介绍 ChainMap 对象的那一部分 (https://docs.python.org/3/library/collections.html#collections.ChainMap) 里有一些具体的使用示例,其中包含了下面这个 Python 变量查询规则的 代码片段:

代码语言:javascript
复制
import builtins 
pylookup = ChainMap(locals(), globals(), vars(builtins))

collections.Counter

这个映射类型会给键准备一个整数计数器。每次更新一个键的时候 都会增加这个计数器。所以这个类型可以用来给可散列表对象计数,或 者是当成多重集来用——多重集合就是集合里的元素可以出现不止一 次。Counter 实现了 + 和 - 运算符用来合并记录,还有像 most_common([n]) 这类很有用的方法。most_common([n]) 会按照次 序返回映射里最常见的 n 个键和它们的计数,详情参阅文档 (https://docs.python.org/3/library/collections.html#collections.Counter)。

  • 下面的小例子利用 Counter 来计算单词中各个字母出现的次数:
代码语言:javascript
复制
import collections

ct = collections.Counter('abracadabra')
print(ct)
>>>
Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
<<<

ct.update('aaaaazzz')
print(ct)
>>>
Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
<<<

print(ct.most_common(2))
>>>
[('a', 10), ('z', 3)]
<<<

colllections.UserDict

这个类其实就是把标准 dict 用纯 Python 又实现了一遍。 跟 OrderedDict、ChainMap 和 Counter 这些开箱即用的类型不 同,UserDict 是让用户继承写子类的。

  • 就创造自定义映射类型来说,以 UserDict 为基类,总比以普通的 dict 为基类要来得方便。更倾向于从 UserDict 而不是从 dict 继承的主要原因是,后者有时 会在某些方法的实现上走一些捷径,导致我们不得不在它的子类中重写 这些方法,但是 UserDict 就不会带来这些问题。
  • 另外一个值得注意的地方是,UserDict 并不是 dict 的子类,但是 UserDict 有一个叫作 data 的属性,是 dict 的实例,这个属性实际上 是 UserDict 最终存储数据的地方。这样做的好处是,UserDict 的子类就能在实现 __setitem__ 的时候避免不必要的递 归,也可以让 __contains__ 里的代码更简洁。
  • 下面用 userdict 重写 strkeydict
代码语言:javascript
复制
import collections
class StrKeyDict(collections.UserDict):
    def __missing__(self, key):
        if isinstance(key, str): 
            raise KeyError(key) 
        return self[str(key)]
    def __contains__(self, key): 
        return str(key) in self.data
    def __setitem__(self, key, item): 
        self.data[str(key)] = item

不可变映射类型

标准库里所有的映射类型都是可变的,但有时候你会有这样的需求,比如不能让用户错误地修改某个映射。

从 Python 3.3 开始,types 模块中引入了一个封装类名叫 MappingProxyType。如果给这个类一个映射,它会返回一个只读的映 射视图。虽然是个只读视图,但是它是动态的。这意味着如果对原映射 做出了改动,我们通过这个视图可以观察到,但是无法通过这个视图对 原映射做出修改。

  • 用 MappingProxyType 来获取字典的只读实例:
代码语言:javascript
复制
from types import MappingProxyType
d = {1:'A'}
d_proxy = MappingProxyType(d)
print(d_proxy)
>>>
{1: 'A'}
<<<

print(d_proxy[1])
>>>
A
<<<

# d_proxy[2] = 'x'
>>>
发生异常: TypeError
'mappingproxy' object does not support item assignment
  File "G:\Active\Python_Practise\fluent python\chapter-2\core.py", line 8, in <module>
    d_proxy[2] = 'x'
<<<

d[2] = 'B'
print(d_proxy)
>>>
{1: 'A', 2: 'B'}
<<<

参考资料

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

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