★莫听穿林打叶声,何妨吟啸且徐行。竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。 ——苏轼 ”
将字符串、列表和元组视为序列,是因为组成它们的成员具有顺序。这是对 Python 内置对象归类的一种方式。在有的资料中,还提出了“基础对象类型”的类别,包括整数类型、浮点数类型、字符串类型和布尔类型。所以,根据对象的不同特点,可以有不同的聚类结果。本章中的“容器”,也是一种归类方式,一般认为包括列表、元组和字典、集合(含可变集合和不变集合),前两种对象已经在第4章学习过,这里将开始学习后两种。诚然,读者也可以创造其他的归类方式。
假设有一种需求,要存储城市和电话区号,用前面已经学习过的知识,可以这么做:
>>> cities = ['soochow', 'hangzhou', 'shagnhai']
>>> phones = ['0512', '0571', '021']
为了让城市和区号能对应起来,在创建列表的时候必须按照同样的索引顺序。若要显示 'soochow'
的电话号码,必须通过每个列表的索引获取:
>>> print(f"{cities[0]}: {phones[0]}")
soochow: 0512
类似这样,一个对象与另外一个对象之间建立对应关系,也是日常生活和生产中常见的事情,比如建立员工的姓名和工资、奖金之间的对应关系,建立学生和各个科目考试成绩之间的对应关系等等。既然如此司空见惯,Python 必然要有内置对象类型,这就是字典( Dictionary )——印刷的字典(比如《新华字典》)就是对应关系的典型代表。
在此之前,已经用引号创建了字符串、用圆括号创建了元组,用方括号创建了列表,低头看看键盘,按照此思路发展,并且排除在其他地方已经使用的符号——比如 *
等,如果选用一个用于创建字典的符号,最可能用哪一个?
Python 发明人选择了 { }
,你是否也想到了这个?如果是,则英雄所见略同;如果不是,也要认可此规定。
>>> d = {"name": "laoqi", "age": 29} # (1)
>>> type(d)
<class 'dict'>
>>> d
{'name': 'laoqi', 'age': 29}
注释(1)创建了一个字典对象,并用变量 d
引用此对象。从 type(d)
的返回值可知,Python 中以 dict
表示字典(或字典类型)。下面参照图5-1-1,理解字典的组成和要求:
{ }
包裹。{}
里面的成员是“键值对”,键值对与键值对之间用英文状态的逗号分割。图5-1-1 字典的组成
字典中的键值对,不能随心所欲地创立——本书的目录和页码之间也是一种对应关系,不能乱写——有如下要求:
比如,如果创建这样的字典:
>>> {'name': 'laoqi', 'name': 'zhangsan'}
{'name': 'zhangsan'}
不会报错,但是结果会“最后一个有效”——“键”是键值对的唯一标识。
至此,在已经学过的 Python 内置对象类型中,能够作为键值对中“键”的有:数字(整数、浮点数、复数)、字符串、元组。
>>> {1: 'first', (1,2,3): [1,2,3], 3.14: {} }
{1: 'first', (1, 2, 3): [1, 2, 3], 3.14: {}}
如果用列表作为键,会怎样呢?
>>> {[1, 2, 3]: "python"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
出现了 TypeError
异常,特别注意看提示信息,告诉我们出问题的根源在于列表是 unhashable
类型。这是什么意思?简要说明:
所以,字典也不能作为键值对的键。
>>> {{1:2}:"python"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
特别提醒,如果用元组作为键值对的键,其成员只能是数字、字符串或者元组,不能包括任何可变对象。例如下面的示例,要仔细观察。
>>> {([1,2],3,4): 'tuple'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> {(([1,2],),3,4): 'tuple'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
成员的成员,并且照此循环,都不能包括可变对象。
老生常谈,既然字典类型的名称是 dict
,Python 的内置函数就会有 dict()
。
>>> dct = dict() # (2)
>>> dct
{}
>>> bool(dct)
False
用注释(2)创建一个空字典(直接用 dct = {}
也能创建空字典),其布尔值是 False
。特别观察,注释(2)中的变量名称,千万不要使用 dict
,否则后患无穷、自食其果。
如果用 dict()
函数创建非空字典,必须使用关键词参数的形式声明对应关系(关键词参数,详见第4章4.2.6节或第7章7.2.1节)。比如:
>>> dict(name='laoqi', age=38)
{'name': 'laoqi', 'age': 38}
所得字典的键就是 dict()
中的关键词参数 name
和 age
——虽然键是字符串,在 dict()
中不要将 name
和 age
写成 'name'
、'age'
,特别要注意此细节。
此外,dict()
还支持以可迭代对象为参数创建字典,例如:
>>> dict([('a', 1), ('lang', 'python')])
{'a': 1, 'lang': 'python'}
此处以列表 [('a', 1), ('lang', 'python')]
为参数,列表中的成员是元组,每个元组内有两个对象,用这种方式约定了两个对象之间的对应关系。
在理解了字典的创建方法之后,读者也应该初步理解“容器”的含义。不论列表,元组还是字典,里面的可以放很多个成员(容器里面的“东西”),每个成员之间用逗号分隔。第4章曾经提到过“列表是个筐”,“筐”就是容器——容器更显得文雅一些。