• Python基础:映射(字典)


    一、概述

    映射类型(Mapping Types)是一种关联式的容器类型,它存储了对象与对象之间的映射关系。

    字典(dict)是Python中唯一的映射类型,它是存储了一个个 键值对(由  映射到 )的关联容器。其中,(key)必须是可哈希的Python对象,而 (value)可以是任何Python对象。在功能上,Python中的字典类似于C++中的map。

    Python中最强大、最灵活的数据类型当属 列表 和 字典,以下是对这两种数据类型的简单比较:

    比较点列表字典
    表示方法 [],[1, 2] {},{'a': 1, 'b': 2}
    访问元素的方式 索引
    有序性 有序 无序
    可变性 可变 可变
    可操作性 操作丰富 操作丰富
    表征的数据结构 数组、堆栈、队列等 哈希表等

    二、操作

    字典支持的主要操作如下:

    操作说明
    class dict(other) 创建字典(other可以是字典、(key, value)对的迭代器或关键字参数)
    dict.fromkeys(seq[, value]) 创建字典:用序列seq中的元素作为键,值全为value(未指定,则默认为None)
    len(d) 返回字典d的长度(即d中元素的个数)
    d[key] 如果键key在字典d中,则返回其中key对应的值;否则抛出KeyError异常
    d[key] = value 设置d[key]的值为value(存在则修改,不存在则添加)
    del d[key] 如果键key在字典d中,则从字典d中删除d[key];否则抛出KeyError异常
    key in d 如果key在字典d中,返回True;否则,返回False
    key not in d 如果key在字典d中,返回False;否则,返回True
    iter(d) 同iterkeys()
    d.clear() 删除字典d中的所有元素
    d.copy() 返回字典d的浅拷贝
    d.get(key[, default]) 如果key在字典d中,则返回d[key];否则返回default(未指定,则默认为None)
    d.has_key(key) 同key in d(推荐使用key in d)
    d.items() 返回包含字典d中的(key, value)对的列表
    d.iteritems() 迭代版的items():返回迭代器
    d.iterkeys() 迭代版的keys():返回迭代器
    d.itervalues() 迭代版的values():返回迭代器
    d.keys() 返回包含字典d中的键的列表
    d.pop(key[, default]) 如果key在字典d中,则返回并删除d[key];否则返回default(未指定,则抛出KeyError异常)
    d.popitem() 返回并删除字典d中的任意一个元素(如果d为空,则抛出KeyError异常)
    d.setdefault(key[, default]) 如果key在字典d中,则返回d[key];否则执行d[key] = default,并返回default(未指定,则默认为None)
    d.update([other]) 将other中的(key, value)对添加到字典d中(other可以是字典、(key, value)对的迭代器或关键字参数)
    d.values() 返回包含字典d中的值的列表
    d.viewitems() 返回字典d的元素视图
    d.viewkeys() 返回字典d的键视图
    d.viewvalues() 返回字典d的值视图

    以上操作的示例如下:

    >>> a = {'one': 1, 'two': 2, 'three': 3}
    >>> b = dict(one=1, two=2, three=3)
    >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
    >>> d = dict({'three': 3, 'one': 1, 'two': 2})
    >>> a == b == c == d
    True
    >>> d = dict.fromkeys(['a', 'b', 'c'])
    >>> d
    {'a': None, 'c': None, 'b': None}
    >>> d = dict.fromkeys(['a', 'b', 'c'], 6)
    >>> d
    {'a': 6, 'c': 6, 'b': 6}
    >>> len(d)
    3
    >>> d.clear()
    >>> d
    {}
    >>> d = a.copy()
    >>> d
    {'one': 1, 'three': 3, 'two': 2}
    >>> d['three']
    3
    >>> d['four'] = 4
    >>> d
    {'four': 4, 'one': 1, 'three': 3, 'two': 2}
    >>> del d['one']
    >>> d
    {'four': 4, 'three': 3, 'two': 2}
    >>> 'four' in d, 'four' not in d
    (True, False)
    >>> d.has_key('four')
    True
    >>> d.get('one'), d.get('one', 10)
    (None, 10)
    >>> for k in d:
    ...     print k,
    ... 
    four three two
    >>> for k in iter(d):
    ...     print k,
    ... 
    four three two
    >>> for k in d.keys():
    ...     print k,
    ... 
    four three two
    >>> for k in d.iterkeys():
    ...     print k,
    ... 
    four three two
    >>> for k in d.viewkeys():
    ...     print k,
    ... 
    four three two
    >>> for v in d.values():
    ...     print v,
    ... 
    4 3 2
    >>> for v in d.itervalues():
    ...     print v,
    ... 
    4 3 2
    >>> for v in d.viewvalues():
    ...     print v,
    ... 
    4 3 2
    >>> for i in d.items():
    ...     print i,
    ... 
    ('four', 4) ('three', 3) ('two', 2)
    >>> for i in d.iteritems():
    ...     print i,
    ... 
    ('four', 4) ('three', 3) ('two', 2)
    >>> for i in d.viewitems():
    ...     print i,
    ... 
    ('four', 4) ('three', 3) ('two', 2)
    >>> d.setdefault('two')
    2
    >>> d
    {'four': 4, 'three': 3, 'two': 2}
    >>> d.setdefault('one', 1)
    1
    >>> d
    {'four': 4, 'one': 1, 'three': 3, 'two': 2}
    >>> d.update(five=1)
    >>> d
    {'four': 4, 'one': 1, 'five': 1, 'three': 3, 'two': 2}
    >>> d.update({'six': 6})
    >>> d
    {'four': 4, 'five': 1, 'two': 2, 'six': 6, 'three': 3, 'one': 1}
    >>> d.pop('four')
    4
    >>> d
    {'five': 1, 'two': 2, 'six': 6, 'three': 3, 'one': 1}
    >>> d.popitem()
    ('five', 1)
    >>> d
    {'two': 2, 'six': 6, 'three': 3, 'one': 1}
    

    三、字典特性

    1、有序与无序

    从概念上讲,字典提供了这样一种抽象:容器中的元素之间完全独立(于是也没有先后顺序),“键”是访问元素的唯一方式。在这种 抽象层面 上,字典是 无序 的。

    从实现上讲,字典其实是由 哈希表 实现的。而哈希表的基本思想是:通过 哈希函数(hash function)将“键”转换为“索引”,再使用“索引”去访问 连续列表(如C中的数组)中的元素。由此可知,在哈希表中:一方面,元素本质上是存储在一个连续列表中的,因此是 有序 的;另一方面,用户无法确定元素在连续列表中的实际位置(只能使用“键”去访问元素,而“键”与“索引”的映射关系是由哈希函数在内部指定的),因此又是 无序 的。

    因此在 实现层面 上,字典同时具备了 无序 和 有序 的特点:

    • 无序体现在:字典中元素的排列顺序与添加顺序无关
    • 有序体现在:在字典保持不变的情况下,字典中元素的排列顺序是固定的

    字典的哈希表实现

    上图对应的示例如下:

    # 无序
    >>> d = {}
    >>> d['a'] = 1
    >>> d
    {'a': 1}
    >>> d['b'] = 2
    >>> d
    {'a': 1, 'b': 2}
    >>> d['c'] = 3
    >>> d
    {'a': 1, 'c': 3, 'b': 2}
    
    # 有序
    >>> for k in d: # 键的顺序固定
    ...     print k,
    ... 
    a c b
    >>> for v in d.values(): # 值的顺序固定
    ...     print v,
    ... 
    1 3 2
    >>> for i in d.items(): # 元素的顺序固定
    ...     print i,
    ... 
    ('a', 1) ('c', 3) ('b', 2)
    

    2、字典的键

    字典的键具有以下特性:

    1)可哈希的(hashable

    只有 可哈希的 对象才能作为字典的键,一个可哈希的对象必须满足以下两个条件:

    • 该对象在其生命周期内有一个不变的哈希值(需要实现__hash__()方法)
    • 该对象是可比较的(需要实现__eq__()__cmp__()方法)

    Python中可哈希的对象有:

    • 数值、字符串,以及只含有数值或字符串的元组
    • 用户自定义类的实例(默认是可哈希的,也可以通过实现__hash__()__cmp__()来修改默认行为)

    2)哈希等价键

    假设有字典d的两个键:keyA和keyB,我们称keyA和keyB是 哈希等价键(自己杜撰的名词),如果keyA和keyB满足以下两个条件:

    • hash(keyA) == hash(keyB)
    • cmp(keyA, keyB) == 0

    如果keyA和keyB是哈希等价键,那么它们将被视为完全相同的两个键,于是d[keyA]和d[keyB]会指向同一个字典元素。

    例如,1和1.0就满足上述两个条件,因此是哈希等价键:

    >>> hash(1), hash(1.0)
    (1, 1)
    >>> cmp(1, 1.0)
    0
    >>> d = {}
    >>> d[1] = 'int 1'
    >>> d
    {1: 'int 1'}
    >>> d[1.0] = 'float 1'
    >>> d
    {1: 'float 1'}
    

    对于用户自定义的类实例,默认情况下(即没有实现__hash__()__cmp__()时),hash(...)和cmp(...)的结果与 id() 有关(参考 hashable 和 __cmp__())。默认情况下,一个自定义类的任意两个实例都不是哈希等价键:

    >>> class A: pass
    ... 
    >>> a1 = A()
    >>> a2 = A()
    >>> hash(a1), hash(a2)
    (-1064359592, -1064359600)
    >>> cmp(a1, a2)
    1
    >>> d = {}
    >>> d[a1] = 'a1'
    >>> d
    {<__main__.A instance at 0x8f2958c>: 'a1'}
    >>> d[a2] = 'a2'
    >>> d
    {<__main__.A instance at 0x8f2958c>: 'a1', <__main__.A instance at 0x8f2950c>: 'a2'}
    

    如果想要让同一个类的任意两个实例都是哈希等价键,则可以参考以下示例:

    >>> class A:
    ...     def __hash__(self):
    ...         return hash(A)
    ...     def __cmp__(self, other):
    ...         return cmp(self.__hash__(), other.__hash__())
    ... 
    >>> a1 = A()
    >>> a2 = A()
    >>> hash(a1), hash(a2)
    (-1064346499, -1064346499)
    >>> cmp(a1, a2)
    0
    >>> d = {}
    >>> d[a1] = 'a1'
    >>> d
    {<__main__.A instance at 0x8f64a4c>: 'a1'}
    >>> d[a2] = 'a2'
    >>> d
    {<__main__.A instance at 0x8f64a4c>: 'a2'}
    

    类似地,如果想要让一个类的任意一个实例与整数1成为哈希等价键,则可以按照以下方式实现:

    >>> class A:
    ...     def __hash__(self):
    ...         return 1
    ...     def __cmp__(self, other):
    ...         return cmp(self.__hash__(), other.__hash__())
    ... 
    >>> a = A()
    >>> hash(1), hash(a)
    (1, 1)
    >>> cmp(1, a)
    0
    >>> d = {}
    >>> d[1] = 'int 1'
    >>> d
    {1: 'int 1'}
    >>> d[a] = 'instance a'
    >>> d
    {1: 'instance a'}
    

    四、字典视图

    从2.7版本开始,Python中引入了字典视图(Dictionary views)。字典视图 是字典的 动态视图:它们会与字典保持同步,实时反应出字典的变化。字典视图共有3种:键视图(Keys views)、值视图(Values views)和 元素视图(Items views),它们分别由dict.viewkeys()、dict.viewvalues()和dict.viewitems()三个函数返回。

    所有的字典视图都支持以下操作:

    操作说明
    len(dictview) 返回字典的长度
    iter(dictview) 返回(键、值、元素)迭代器
    x in dictview 判断x是否为(键、值、元素)的成员

    此外,因为字典的键是 唯一 且 可哈希的,所以 键视图 还支持 类似集合(set-like)的操作。如果字典的值是 可哈希的,那么 元素视图 也支持这些操作:

    操作说明
    dictview & other 求交集
    dictview | other 求并集
    dictview - other 求差集
    dictview ^ other 求对称差集

    关于字典视图的示例,请参考 Dictionary view objects

    五、应用

    1、模拟switch-case语句

    以下是C中一个使用switch-case语句的示例:

    int select(char c)
    {
        int num = -1;
    
        switch (c)
        {
            case 'a':
                num = 1;
            break;
    
            case 'b':
                num = 2;
            break;
    
            case 'c':
                num = 3;
            break;
    
            default:
                num = 0;
            break;
        }
    
        return num;
    }
    

    Python中没有提供switch-case语句,但使用字典可以轻松实现类似上面的功能:

    d = {'a': 1, 'b': 2, 'c': 3}
    
    # 普通版本
    def select1(c):
        num = -1
    
        if c not in d:
            num = 0
        else:
            num = d[c]
    
        return num
    
    # 惊呆版本
    def select2(c):
        return d.get(c, 0)
    

    2、稀疏矩阵

    使用元组作为字典的键,可以构建类似稀疏矩阵的数据结构:

    >>> matrix = {}
    >>> matrix[(2, 3, 4)] = 88
    >>> matrix[(7, 8, 9)] = 99
    >>> 
    >>> matrix
    {(2, 3, 4): 88, (7, 8, 9): 99}
    >>> 
    >>> x, y, z = 2, 3, 4
    >>> matrix[(x, y, z)]
    88
    

    3、符号表

    实际上,Python本身就在内部大量使用了字典,一个典型的应用就是符号表:

    >>> locals() # 局部符号表 
    {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
    >>> globals() # 全局符号表 
    {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
  • 相关阅读:
    【STM32F407的DSP教程】第47章 STM32F407的IIR带阻滤波器实现(支持逐个数据的实时滤波)
    【STM32H7的DSP教程】第46章 STM32H7的IIR带通滤波器实现(支持逐个数据的实时滤波)
    【STM32F429的DSP教程】第46章 STM32F429的IIR带通滤波器实现(支持逐个数据的实时滤波)
    【STM32F407的DSP教程】第46章 STM32F407的IIR带通滤波器实现(支持逐个数据的实时滤波)
    嵌入式新闻早班车-第21期
    【STM32H7的DSP教程】第45章 STM32H7的IIR高通滤波器实现(支持逐个数据的实时滤波)
    【STM32F429的DSP教程】第45章 STM32F429的IIR高通滤波器实现(支持逐个数据的实时滤波)
    【STM32F407的DSP教程】第45章 STM32F407的IIR高通滤波器实现(支持逐个数据的实时滤波)
    【第3版emWin教程】第32章 emWin6.x的矢量字体(支持汉字全字库,Unicode编码,QSPI Flash方案)
    【第3版emWin教程】第31章 emWin6.x的全字库的实现(GB2312编码,SPI Flash方案)
  • 原文地址:https://www.cnblogs.com/anita-harbour/p/9328614.html
Copyright © 2020-2023  润新知