Python 变量之字典与实战经验
作者: Jim Wang 公众号: 巴博萨船长
Python 标准数据类型
大家好,最近更新比较慢,临近圣诞节和新年,公司的事情也就异常多。连续几天的会议,还要加紧修复bug,为新版本软件的发布做准备。好了言归正传,书接上回。Python 定义了一些标准数据类型,用于存储各种类型的数据。Python有五个标准的数据类型,分别是:
- Numbers(数字)
- String(字符串)
- List(列表)
- Tuple(元组)
- Dictionary(字典)
字典在Python中应该算是最后一个重要的基本变量,出现在代码中的频率也比较高。常被用作为一种可变的数据容器。今天就给大家介绍一下Python最后一个标准数据类型字典,即Dictionary的一些基础知识和在实际应用中的使用技巧。
Dictionary 字典的特征
作为一种可变容器模型,那么字典Dict在声明之后就能够任意被修改,比如添加,删除,或者更改。既然名为字典也就意味着其查询索引方式类如真实意义上的字典。Python的自己由一组键(key)与值(value)组成。两者之间用冒号隔开(:)。组与组之间与逗号(,)隔开。最后用花括号(大括号) “**{}**” 包裹所有的键值组,就得到一个字典实例,如下:
1 | di = {key_1 : value_1, key_2 : value_2, key_3: value_3} |
字典中,每一组键值,其键需要有唯一性,但是其值则不需要。在Python中,字典键值的唯一性就限制了它的数据类型选择范围。结合前面文章所介绍的的标准数据类型,除列表以外:数值型,元组,字符串都能够作为字典类型的键,经过实践可以告诉大家,任何类的实例都可以作为字典的键。因为类一旦实例化,其类实例在内存中的地址具有唯一性,因此也可以作为字典的键,参考下面代码:
1 | class A: |
字典中,每组键值中的值,没有限定,可以是任意的数据类型。1. 键值是否可变,字典并不做约束,仅仅与数据类型本身有关。如下面代码的例子中,元组可以作为一对键值的值,因为元组本身不可变,所以该对键值的值不可变,但是不能因此认为字典的值不可改变。 2. 一对键值中,虽然字典也可以作为键值的值,而且在日常使用的时候也不会出现问题,但是在实际使用的时候,如果作为值的字典中存在bytes类的键值时,当尝试使用deepcopy复制字典实例的时候,可能会引发异常,当然类似的异常也会存在与复制相似结构的列表时诱发。各位可以留个印象,当以后遇见类似问题,或许可以帮助你确定异常诱发的原因。
1 | "str": "String", "list": ["list1", "list2"], "tuple": (1, 2, 3) , "dictionary" : {"a": "1", "b":2}} mydict = { |
总的来说,对于字典中键值对,键是由唯一且不可变的数据类型定义,准确地来说是可以哈希(hashable)的数据类型。值可以为任意数据类型。当同一键值被重复赋值,最后一次值将被采用。
声明后的字典实例,修改添加和改变都很简单。其中为字典中添加一个元素和更改一个元素的书写方式是一样的。如下方代码:如果字典情况位置,键3值的修改和键4值的添加,方法一样。而列表再添加值的时候是需要使用类方法append()的。而如果使用数字作为键值,代码文件就由如d[3] = ‘d’ 的内容, 这样的书写方法不利于代码的标准化,而且类似的需求完全可以由列表来实现。所以个人建议为了代码的标准化,使用字典时,还是应尽量避免数值类型作为键的值,避免代码出现歧义。
1 | 1: "a", 2: "b", 3: "c"} d = { |
字典的删除操作,使用字典的类方法clear()可以删除字典中的所有元素,但是字典实例依旧存在。也可以使用关键字del来实现对字典单一元素和整个字典的清除。注意:使用关键字del删除整个字典,该字典的实例将从内存中清除,使用被清除的字典会引发异常。如下面代码:
1 | 1: 'a', 2: 'b', 3: 'd', 4: 'e'} d = { |
Dictionary 字典的索引
Python中字典键值的索引总的来说有两种方法,一种使用方括号和键,类似列表的方法来索引和访问字典中的元素。第二种是使用get()类方法和键来索引和访问,代码如下:
1 | 1: 'a', 2: 'b', 3: 'd', 4: 'e'} d = { |
两种方法在效率上并没有差别,早前读过一篇文章讨论两种索引方式的效率。结果如下,结果显示使用方括号更直接高效。个人建议大家将图示的结果仅作为一个参考,因为也有Python开发人员有不同意见,认为实验方式有问题。
在实际应用的时候,我个人觉得两种方法的效率其实并没有太大差别,更值得关注的是get()方法能够更好地避免因为键不存在引起的索引异常。如下面代码:
1 | 1: 'a', 2: 'b', 3: 'd', 4: 'e'} d = { |
由上述代码可以发现,在遇到字典中不存在的键的问题的时候,方括号+键的方式会引发异常,为了避免异常还要添加代码(通常为if语句)来检测该字典中是否存在所求键值组。而使用get()方法则能避免引发这个异常,当字典中不存在所求键值组的时,使用该方法返回空,或者你也可以给定第二个变量作为默认值,当该键值不存在则会返回默认值。在实际使用中该方法优选,可以很大程度地减少代码数量。
在这里我给大家介绍一个Python字典索引的实战经验,具体方法如下方代码。假如一个字典有数字和字符串混合键,想要得到所有数字键的键值组。经典方法为,索引字典中的每一个键值组,检查键的数据类型,将符合条件的键值组的值加入一个列表里面,最终就可以得到所有符合要求的键值组的值的组合。
1 | '1': "a", 1:"b", '2': "c", 2 : "d", '3': "e", 3: "f"} d = { |
使用上述方法,可以避免索引整个字典,代码简洁有效。这里值得关注的是使用filter()+lambda关键字来筛选一个列表,和使用map()函数一次性地用不同参数调用同一函数(在这里为字典的get()方法)。这样的方法或许可以提供一种不同的解决问题的思路。
索引的特殊情况,历遍字典所有键值组。经典方法为for + in 的组合来进行迭代。请参考下方代码。
1 | for key in d: |
该种方法也有效,但是不推荐使用。主要原因在于,底层代码要检验键值的唯一性,该方法会增加发生异常的频率。还有一个原因是for循环中的d[key] 会导致键再次被哈希,当字典较大时,这样的操作会消耗更多的时间。
我个人比较推荐使用下面的方法,这样的方法同时迭代键与值,而且更见安全。这在Python 2.7 中常被使用:
1 | for key, value in d.iteritems(): |
Python 3.0 会使用下面的方法:
1 | for key, value in d.items(): |
关于字典的内置函数和类方法
字典作为Python的标准数据类型,Python这种语言自然为其准备了一些内置方法,常见的主要如下:
- len(dict) 函数:用于得到字典的长度,因为为键值组,所以键的数量和值的数量相当。
- str(dict) 函数:用于输出字典可打印的字符串,其表示内容,可通过继承字典类型, 复写repr(self)类函数来格式化输出内容。
- cmp(dict1, dict2)函数:用于比较字典的键值组是否完全一致,如果相同则返回真, 否则为假。
字典在Python中也算是一种类,既然是类就有类方法。上文中介绍了一些常见的类方法比如使用键得到值的get()方法,清除字典内所有元素的clear()方法和得到字典内所有键值组键的方法keys()。 除此之外常用的方法还有:
dict.copy() 类方法: 用于浅复制一个字典, 注。
dict.items() 类方法:返回值为该字典”(键,值)“样式的元组组成的列表 ,注。
dict.update(dict2) 类方法:使用dict2中的值,来更新dict中有相同键的键
值组的值。
dict.values() 类方法:返回字典中所有值组成的列表。
dict.has_key(key) 类方法:用于判断字典中是否含有该键,有为true,否则为假。
dict.pop(key, default) 类方法:该方法与get()相似,删除一组键值,如果该键不
存在则返回default值。 注: Python 2.x中有iteritems方法,在Python 3.0 中该方法被items()替代。 关于浅复制和深复制的内容,我将为在以后的文章中介绍给大家。
使用Python语言的内置方法和字典的类方法并结合一下编程技巧,我相信,各位读者能够正确使用字典来解决自己在项目中遇见的问题, 并在完成项目的同时会发现一些新的技巧,进而不断地提高自己的代码质量和代码效率。
Python基本数据类型中的字典和其使用技巧今天就介绍到这里,我也会尽我所能提高更新频率。努力归纳自己在工作中遇见的问题,并把自己找到的解决方法介绍给大家。
文章首发于 Jim Wang's blog , 转载文章请务必以超链接形式标明文章出处,作者信息及本版权声明。