美文网首页Python从小白到大牛
《Python从小白到大牛》第9章 数据结构

《Python从小白到大牛》第9章 数据结构

作者: tony关东升 | 来源:发表于2018-08-21 11:11 被阅读41次

    《Python从小白到大牛》已经上市!

    《Python从小白到大牛》

    当你有很多书时,你会考虑买一个书柜,将你的书分门别类摆放进入。使用了书柜不仅仅使房间变得整洁,也便于以后使用书时方便查找。在计算机程序中会有很多数据,这些数据也需要一个容器将他们管理起来,这就是数据结构。常见的数据结构:数组(Array)、集合(Set)、列表(List)、队列(Queue)、链表(Linkedlist)、树(Tree)、堆(Heap)、栈(Stack)和字典(Dictionary)等结构。

    Python中数据容器主要有:序列、集合和字典。

    注意
    Python中并没有数组结构,因为数组要求元素类型是一致的。而Python作为动态类型语言,不强制声明变量的数据类型,也不能强制检查元素的数据类型。所以Python中没有数组结构。

    元组

    元组(tuple)是一种序列(sequence)结构,下面先来介绍一些序列。

    序列

    序列(sequence)是一种可迭代的[1],元素是有序的,可以重复出现的数据结构。序列可以通过索引访问元素。图9-1是一个班级序列,其中有一些学生,这些学生是有序的,顺序是他们被放到序列中的顺序,可以通过序号访问他们。这就像老师给进入班级的人分配学号,第一个报到的是“张三”,老师给他分配的是0,第二个报到的是“李四”,老师给他分配的是1,以此类推,最后一个序号应该是“学生人数-1”。

    图9-1 序列

    序列包括的结构有:列表(list)、字符串(str)、元组(tuple)、范围(range)、和字节序列(bytes)。序列可进行的操作有:索引、分片、加和乘。

    1. 索引操作

    序列中第一个元素的索引是0,其他元素的索引是第一个元素的偏移量。可以有正偏移量,称为正值索引;也可以有负偏移量,称为负值索引。正值索引最后一个元素索引是“序列长度-1”,负值索引最后一个元素索引是“-1”。例如Hello字符串,它的正值索引如图9-2(a)所示,它的负值索引如图9-2(b)所示。

    图9‑2 索引

    访问序列中的元素的通过索引下标访问的,即中括号[index]方式访问。在Python
    Shell中运行示例如下:

    >>> a = 'Hello'
    >>> a[0]
    'H'
    >>> a[1]
    'e'
    >>> a[4]
    'o'
    >>> a[-1]
    'o'
    >>> a[-2]
    'l'
    >>> a[5] 
    Traceback (most recent call last):
      File "<pyshell#2>", line 1, in <module>
        a[5]
    IndexError: string index out of range
    >>> max(a)
    'o'
    >>> min(a)
    'H'
    >>> len(a)
    5
    

    a[0]是访问序列第一个元素,最后一个元素的索引可以是4或-1。但是索引超过范围,则会发生IndexError错误。另外,获取序列的长度使用函数len,类似的序列还有max和min函数,max函数返回最后一个元素,min函数返回第一个元素。

    1. 序列的加和乘

    下面看看序列的加和乘,在前面第7章介绍+和*运算符时,提到过他们可以应用于序列。+运算符可以将两个序列连接起来,*运算符可以将重复多次。

    在Python Shell中运行示例:

    >>> a = 'Hello'
    >>> a * 3
    'HelloHelloHello'
    >>> print(a)
    Hello
    >>> a += ' '
    >>> a += 'World'
    >>> print(a)
    Hello World
    
    1. 序列分片

    序列的分片(Slicing)就是从序列中切分出小的子序列。分片使用分片运算符,分片运算符有两种形式:

    • [start:end]。start是开始索引,end是结束索引。

    • [start:end:step]。start是开始索引,end是结束索引,step是步长,步长是在分片时获取元素的间隔。步长可以为正整数,也可为负整数。

    注意
    切下的分片包括start位置元素,但不包括end位置元素,start和end都可以省略。

    在Python Shell中运行示例代码如下:

    >>> a[1:3]
    'el'
    >>> a[:3]   
    'Hel'
    >>> a[0:3]
    'Hel'
    >>> a[0:]   
    'Hello'
    >>> a[0:5]
    'Hello'
    >>> a[:]    
    'Hello'
    >>> a[1:-1] 
    'ell'
    

    上述代码表达式a[1:3]是切出1~3之间的子字符串,注意不包括3,所以结果是el。表达式a[:3]省略了开始索引,默认开始索引是0,所以a[:3]与a[0:3]分片结果是一样的。表达式a[0:]省略了结束索引,默认结束索引是序列的长度,即5。所以a[0:]
    与a[0:5]分片结果是一样的。表达式a[:]是省略了开始索引和结束索引,a[:]与a[0:5]结果一样。

    另外,表达式a[1:-1]使用了负值索引,对照图9-1所示,不难计算出a[1:-1]结果是ell。

    分片时使用[start:end:step]可以指定步长(step),步长与当次元素索引、下次元素索引之间的关系如下:

    >   下次元素索引 = 当次元素索引 + 步长
    

    在Python Shell中运行示例代码如下:

    >>> a[1:5]
    'ello'
    >>> a[1:5:2]
    'el'
    >>> a[0:3]
    'Hel'
    >>> a[0:3:2]
    'Hl'
    >>> a[0:3:3]
    'H'
    >>> a[::-1]
    'olleH'
    

    表达式a[1:5]省略了步长参数,步长默认值是1。表达式a[1:5:2]是步长为2,结果是el。a[0:3]分片后的字符串是Hel。而a[0:3:3]是步长为3,分片结果H字符了。当步长为负数时比较麻烦,负数时是从右往左获取元素,所以表达式a[::-1]分片的结果是原始字符串的倒置。

    创建元组

    元组(tuple)是一种不可变序列,一旦创建就不能修改。创建元组可以使用tuple([iterable])函数或者直接用逗号(,)将元素分隔。

    在Python Shell中运行示例代码如下:

    >>> 21,32,43,45             ①
    (21, 32, 43, 45)
    >>> (21, 32, 43, 45)            ②
    (21, 32, 43, 45)
    >>> a = (21,32,43,45)
    >>> print(a)
    (21, 32, 43, 45)
    >>> ('Hello', 'World')      ③
     ('Hello', 'World')
    >>> ('Hello', 'World', 1,2,3)④
    ('Hello', 'World', 1, 2, 3)
    >>> tuple([21,32,43,45])      ⑤
    (21, 32, 43, 45)
    

    代码第①行创建了一个有4个元素的元组,创建元组时使用小括号把元素包裹起来不是必须的。代码第②行使用括号将元素包裹起来,这只是为了提高程序的可读性。Python中没有强制声明数据类型,因此元组中的元素可以是任何数据类型,代码第③行创建是一个字符串元组,代码第④行是创建字符串和整数混合的元组。

    另外,元组还有通过tuple([iterable])函数创建,参数iterable是任何可迭代对象。代码第⑤行是使用tuple()函数创建元组对象,实参[21,32,43,45]是一个列表,列表是可迭代对象,可以作为tuple()函数参数创建元组对象。

    创建元组还需要注意如下极端情况:

    >>> a = (21)
    >>> type(a)
    <class 'int'>
    >>> a = (21,)
    >>> type(a)
    <class 'tuple'>
    >>> a = ()  
    >>> type(a)
    <class 'tuple'>
    

    从上述代码可见,如果一个元组只有一个元素时,后面的逗号不能省略,即(21,)表示的是只有一个元素的元组,而(21)表示的是一个整数。另外,()可以创建空元组。

    访问元组

    元组做为序列可以通过下标索引访问元素,也可以对其进行分片。在Python
    Shell中运行示例代码如下:

    >>> a =  ('Hello', 'World', 1,2,3)  ①
    >>> a[1]
    'World'
    >>> a[1:3]
    ('World', 1)
    >>> a[2:]
    (1, 2, 3)
    >>> a[:2]
    ('Hello', 'World')
    

    上述代码第①行是元组a,a[1]是访问元组第二个元素,表达式a[1:3]、a[2:]和a[:2]都是进行分片操作。

    元组还可以进行拆包(Unpack)操作,就是将元组的元素取出赋值给不同变量。在Python Shell中运行示例代码如下:

    >>> a =  ('Hello', 'World', 1,2,3)
    >>> str1, str2, n1,n2, n3 = a   ①
    >>> str1
    'Hello'
    >>> str2
    'World'
    >>> n1
    1
    >>> n2
    2
    >>> n3
    3
    >>> str1, str2, *n = a  ②
    >>> str1
    'Hello'
    >>> str2
    'World'
    >>> n
    [1, 2, 3]
    >>> str1,_,n1,n2,_ = a ③
    

    上述代码第①行是将元组a进行拆包操作,接收拆包元素的变量个数应该等于元组个数相同。接收变量个数也可以少于元组个数,代码第②行接收变量个数只有3个,最后一个很特殊,变量n前面有星号,表示将剩下的元素作为一个列表赋值给变量n。另外,还可以使用下划线指定哪些元素不取值,代码第行是不取第二个和第五个元素。

    遍历元组

    遍历元组一般是使用for循环,示例代码如下:

    # coding=utf-8
    # 代码文件:chapter9/ch9.1.4.py
    
    
    a = (21, 32, 43, 45)
    
    for item in a:              ①
        print(item)
    
    print('-----------')
    for i, item in enumerate(a):    ②
        print('{0} - {1}'.format(i, item))
    

    输出结果如下:

    21
    32
    43
    45
    -----------
    0 - 21
    1 - 32
    2 - 43
    3 – 45
    

    一般情况下遍历目的只是取出每一个元素值,见代码第①行的for循环。但有时需要在遍历过程中同时获取索引,则可以使用代码第②行的for循环,其中enumerate(a)函数可以获得元组对象,该元组对象有两个元素,第一个元素是索引,第二个元素是数值。所以i,
    item是元组拆包过程,最后变量i是元组a的当前索引,item是元组a的当前元素值。

    注意
    本节虽然介绍的是元组的遍历,上述遍历方式适合于所有序列,如字符串、范围和列表等。

    列表

    列表(list)也是一种序列结构,与元组不同列表具有可变性,可以追加、插入、删除和替换列表中的元素。

    列表创建

    创建列表可以使用list([iterable])函数,或者用中括号[]将元素包裹,元素之间用逗号分隔。在Python Shell中运行示例代码如下:

    >>> [20, 10, 50, 40, 30]    ①
    [20, 10, 50, 40, 30]
    >>> []  
    []
    >>> ['Hello', 'World', 1, 2, 3] ②
    ['Hello', 'World', 1, 2, 3]
    >>> a = [10]        ③
    >>> type(a)
    <class 'list'>
    >>> a = [10,]       ④
    >>> type(a)
    <class 'list'>
    >>> list((20, 10, 50, 40, 30))  ⑤
    [20, 10, 50, 40, 30]
    

    上述代码第①行创建一个有5个元素的列表,注意中括号不能省略,如果省略了中括号那就变成了元组了。创建空列表是[]表达式。列表中可以放入任何对象,代码第②行是创建一个字符串和整数混合的列表。代码第③行是创建只有一个元素的列表,中括号不能省略。另外,无论是元组还是列表,每一个元素后面都跟着一个逗号,只是最后一个元素的逗号经常是省略的,代码第④行最后一个元素没有省略逗号。

    另外,列表还有通过list([iterable])函数创建,参数iterable是任何可迭代对象。代码第⑤行是使用list()函数创建列表对象,实参(20,
    10, 50, 40,
    30)是一个元组,元组是可迭代对象,可以作为list()函数参数创建列表对象。

    追加元素

    列表中追加单个元素可以使用append()方法追加单个元素。如果想追加另一列表,可以使用+运算符或extend()方法。

    append()方法语法:

    list.append(x)
    

    其中x参数是要追加单个元素值。

    extend()方法语法:

    list.extend(t)
    

    其中t参数是要追加的另外一个列表。

    在Python Shell中运行示例代码如下:

    >>> student_list = ['张三', '李四', '王五']   
    >>> student_list.append('董六')       ①
    >>> student_list
    ['张三', '李四', '王五', '董六']
    >>> student_list += ['刘备', '关羽']        ②
    >>> student_list
    ['张三', '李四', '王五', '董六', '刘备', '关羽']
    >>> student_list.extend(['张飞', '赵云'])   ③
    >>> student_list
    ['张三', '李四', '王五', '董六', '刘备', '关羽', '张飞', '赵云']
    

    上述代码中第①行使用了append方法,在列表后面追加一个元素,append()方法不能同时追加多个元素。代码第②行是利用+=运算符追加多个元素,能够支持+=运算是因为列表支持+运算。代码第③行是使用extend()方法追加多个元素。

    插入元素

    插入元素可以使用列表的insert()方法,该方法可以在指定索引位置,插入一个元素。insert()方法语法:

    list.insert(i, x)
    

    其中参数i是要插入的索引,参数x是要插入的元素数值。

    在Python Shell中运行示例代码如下:

    >>> student_list = ['张三', '李四', '王五']
    >>> student_list.insert(2, '刘备')
    >>> student_list
    ['张三', '李四', '刘备', '王五'] 
    

    上述代码中student_list调用insert方法,在索引2位置插入一个元素,新元素的索引为2。

    替换元素

    列表具有可变性,其中的元素替换,替换元素很简单,通过列表下标索引元素放在赋值符号(=)左边,进行赋值即可替换。在Python
    Shell中运行示例代码如下:

    >>> student_list = ['张三', '李四', '王五']
    >>> student_list[0] = "诸葛亮"
    >>> student_list
    ['诸葛亮', '李四', '刘备', '王五']
    

    其中student_list[0] = "诸葛亮"是替换列表student_list的第一个元素。

    删除元素

    列表中实现删除元素的方式有两种:一种是使用列表的remove()方法;另一种是使用列表的pop()方法。

    1. remove()方法

    remove()方法从左往右查找列表中的元素,如果找到匹配元素则删除,注意如果找到多个匹配元素,只是删除第一个。如果没有找到则会抛出错误。

    remove()方法语法:

    list.remove(x)
    

    其中x参数是要找到元素值。

    使用remove()方法删除元素,示例代码如下:

    >>> student_list = ['张三', '李四', '王五', '王五']
    >> student_list.remove('王五')
    >>> student_list
    ['张三', '李四', '王五']
    >>> student_list.remove('王五')
    >>> student_list
    ['张三', '李四']
    
    1. pop()方法

    pop()方法也会删除列表中的元素,但它会将成功删除的元素返回。pop()方法语法如下:

    item = list.pop([i])
    

    参数i是指定删除元素的索引,i可以省略,表示删除最后一个元素。返回值item是删除的元素。

    使用pop()方法删除元素示例代码如下:

    >>> student_list = ['张三', '李四', '王五']
    >>> student_list.pop()
    '王五'
    >>> student_list
    ['张三', '李四']
    >>> student_list.pop(0)
    '张三'
    >>> student_list
    ['李四']
    

    其他常用方法

    前面介绍列表追加、插入和删除时,已经介绍了一些方法。事实上列表还有很多方法,本节再介绍几个常用的方法。包括:

    • reverse()。倒置列表。

    • copy()。复制列表。

    • clear()。清除列表中的所有元素。

    • index(x[, i[,
      j]])。返回查找x第一次出现的索引,i是开始查找索引,j是结束查找索引。该方法继承自序列,元组和字符串也可以使用该方法。

    • count(x)。返回x出现的次数。该方法继承自序列,元组和字符串也可以使用该方法。

    在Python Shell中运行示例代码如下:

    >>> a = [21, 32, 43, 45]
    >>> a.reverse()     ①
    >>> a
    [45, 43, 32, 21]
    >>> b = a.copy()    ②
    >>> b
    [45, 43, 32, 21]
    >>> a.clear()           ③   
    >>> a
    []
    >>> b
    [45, 43, 32, 21]
    >>> a = [45, 43, 32, 21, 32]
    >>> a.count(32)     ④
    2
    >>> student_list = ['张三', '李四', '王五']
    >>> student_list.index('王五')    ⑤
    2
    >>> student_tuple = ('张三', '李四', '王五')
    >>> student_tuple.index('王五')   ⑥
    2
    >>> student_tuple.index('李四', 1 , 2)
    1
    

    上述代码中第①行是调用reverse()方法将列表a倒置。代码第②行是调用copy()方法复制a,并赋值给b。代码第③行是清除a中元素。代码第④行是返回a列表中32元素的个数。代码第⑤行是返回'王五'在student_list列表中的位置。代码第⑥行是返回'王五'在student_tuple元组中的位置。

    列表推导式

    Python中有一种特殊表达式——推导式,它可以将一种数据结构作为输入,经过过滤、计算等处理,最后输出另一种数据结构。根据数据结构的不同分为:列表推导式、集合推导式和字典推导式。本节先介绍列表推导式。

    如果想获得0~9中偶数的平方数列,那么可以通过for循环实现,代码如下:

    # coding=utf-8
    # 代码文件:chapter9/ch9.2.7.py
    
    n_list = []
    for x in range(10):
        if x % 2 == 0:
            n_list.append(x ** 2)
    print(n_list)
    

    输出结构如下:

    [0, 4, 16, 36, 64]
    

    0~9中偶数的平方数列可以通过列表推导式实现,代码如下:

    n_list = [x ** 2 for x in range(10) if x % 2 == 0]  ①
    print(n_list)
    

    上述代码其中代码第行就是列表推导式,输出的结果与for循环是一样的。图9-3所示是列表推导式语法结构,其中in后面的表达式是“输入序列”;for前面的表达式是“输出表达式”它运算结果会保存一个新列表中;if条件语句是过滤输入序列,符合条件的才传递给输出表达式,“条件语句”是可以省略的,也是所有元素都传递给输出表达式。

    图9‑3 索引

    条件语句可以包含多个条件,如果想找出0~99之间的偶数,而且可以被5整除数列,实现代码如下:

    n_list = [x for x in range(100) if x % 2 == 0 if x % 5 == 0]  
    print(n_list)
    

    列表推导式的条件语句有两个if x % 2 == 0和if x % 5 == 0,可见他们“与”的关系。

    集合

    集合(set)是一种可迭代的、无序的、不能包含重复元素的数据结构。图9-4是一个班级的集合,其中包含一些学生,这些学生是无序的,不能通过序号访问,而且不能有重复的同学。

    图9-4 集合

    提示
    如果与序列比较,序列中的元素是有序的,可以重复出现,而集合中是无序的,不能重复的元素。序列强调的是有序,集合强调的是不重复。当不考虑顺序,而且没有重复的元素时,序列和集合可以互相替换。

    集合又分为可变集合(set)和不可变集合(frozenset)。

    创建可变集合

    可变集合类型是set,创建可变集合可以使用set([iterable])函数,或者用大括号{}将元素包裹,元素之间用逗号分隔。在Python
    Shell中运行示例代码如下:

    >>> a = {'张三', '李四', '王五'}      ①
    >>> a
    {'张三', '李四', '王五'}
    >>> a = {'张三', '李四', '王五', '王五'}②
    >>> len(a)
    3
    >>> a
    {'张三', '李四', '王五'}
    >>> set((20, 10, 50, 40, 30)) ③
    {40, 10, 50, 20, 30}
    >>> b = {}          ④
    >>> type(b)
    <class 'dict'>
    >>> b = set()       ⑤
    >>> type(b)
    <class 'set'>
    

    上述代码第①行是使用大括号创建集合,如果元素有重复的会怎样呢?代码第②行包含有重复的元素,创建时会剔除重复元素。代码第③行是使用set()函数创建集合对象。如果要创建一个空的集合不能使用{}表示,见代码第④行b并不是集合而是字典,而是使用空参数的set()函数,见代码第⑤行。

    提示
    要获得集合中元素的个数,可以使用len()函数,注意len()是函数不是方法,本例中len(a)表达式返回集合a的元素个数。

    修改可变集合

    可变集合类似于列表,可变集合内容可以被修改,可以插入和删除元素。修改可变集合几个常用的方法。包括:

    • add(elem)。添加元素,如果元素已经存在,则不能添加,不会抛出错误。

    • remove(elem)。删除元素,如果元素不存在,则抛出错误。

    • discard(elem)。删除元素,如果元素不存在,不会抛出错误。

    • pop()。删除返回集合中任意一个元素,返回值是删除的元素。

    • clear()。清除集合。

    在Python Shell中运行示例代码如下:

    >>> student_set = {'张三', '李四', '王五'}
    >>> student_set.add('董六')
    >>> student_set
    {'张三', '董六', '李四', '王五'}
    >>> student_set.remove('李四')
    >>> student_set
    {'张三', '董六', '王五'}
    >>> student_set.remove('李四')    ①
    Traceback (most recent call last):
      File "<pyshell#144>", line 1, in <module>
        student_set.remove('李四')
    KeyError: '李四'
    >>> student_set.discard('李四')   ②
    >>> student_set
    {'张三', '董六', '王五'}
    >>> student_set.discard('王五')
    >>> student_set
    {'张三', '董六'}
    >>> student_set.pop()       
    '张三'
    >>> student_set
    {'董六'}
    >>> student_set.clear()
    >>> student_set
    set()
    

    上述代码第①行使用remove()方法删除元素时,由于要删除的'李四'已经不在集合中,所以会抛出错误。而同样是删除集合中不存在的元素discard()方法不会抛出错误,见代码第②行。

    遍历集合

    集合是无序的,没有索引,不能通过下标访问单个元素。但可以遍历集合,访问集合每一个元素。

    遍历集合一般是使用for循环,示例代码如下:

    # coding=utf-8
    # 代码文件:chapter9/ch9.3.3.py
    
    student_set = {'张三', '李四', '王五'}
    
    for item in student_set:     
        print(item)
    
    print('-----------')
    for i, item in enumerate(student_set):    ①
        print('{0} - {1}'.format(i, item))
    

    输出结果如下:

    张三
    王五
    李四
    -----------
    0 - 张三
    1 - 王五
    2 - 李四
    

    上述中使用for循环遍历集合,代码第①行的for循环中使用了enumerate()函数,该还是在9.1.4节遍历元组时已经介绍过了,但是需要注意的是,此时变量i不是索引,只是遍历集合的次数。

    不可变集合

    不可变集合类型是frozenset,创建不可变集合使用frozenset([iterable])函数,不能使用大括号{}。在Python Shell中运行示例代码如下:

    >>> student_set = frozenset({'张三', '李四', '王五'})  ①  
    >>> student_set
    frozenset({'张三', '李四', '王五'})
    >>> type(student_set)
    <class 'frozenset'>
    >>> student_set.add('董六')   ②
    Traceback (most recent call last):
      File "<pyshell#168>", line 1, in <module>
        student_set.add('董六')
    AttributeError: 'frozenset' object has no attribute 'add'
    >>> a = (21, 32, 43, 45)
    >>> seta = frozenset(a) ③
    >>> seta
    frozenset({32, 45, 43, 21})
    

    上述代码第①行是创建不可变集合,frozenset()的参数{'张三', '李四',
    '王五'}是另一个集合对象,因为集合也是可迭代对象,可以作为frozenset()的参数。代码第③函数使用的了一个元组a作为frozenset()的参数。

    由于创建的是不变集合,不能被修改,所以视图修改发生错误,见代码第②行,使用add()发生错误。

    集合推导式

    集合推导式与列表推断式类似,区别只是输出结构是集合。修改9.2.7节代码如下:

    # coding=utf-8
    # 代码文件:chapter9/ch9.3.5.py
    
    n_list = {x for x in range(100) if x % 2 == 0 if x % 5 == 0}
    print(n_list)
    

    输出结构如下:

    {0, 70, 40, 10, 80, 50, 20, 90, 60, 30}
    

    由于集合是不能有重复元素的,集合推导式输出结果会过滤掉重复的元素,示例代码如下:

    input_list = [2, 3, 2, 4, 5, 6, 6, 6]
    
    n_list = [x ** 2 for x in input_list] ①
    print(n_list)
    
    n_set = {x ** 2 for x in input_list} ②
    print(n_set)
    

    输出结构如下:

    [4, 9, 4, 16, 25, 36, 36, 36]
    {4, 36, 9, 16, 25}
    

    上述代码第①行是列表推导式。代码第②行是集合推导式,从结果可见没有重复的元素。

    字典

    字典(dict)是可迭代的、可变的数据结构,通过键来访问元素的数据结构。字典结构比较复杂,它是由两部分视图构成的:一个是键(key)视图;另一个是值(value)视图。键视图不能包含重复元素的,而值集合可以,键和值是成对出现的。

    图9-5所示是字典结构的“国家代号”。键是国家代号,值是国家。

    图9-5 字典

    提示
    字典更适合通过键快速访问值,就像查英文字典一样,键就是要查的英文单词,而值是英文单词的翻译和解释等内容。有的时候,一个英文单词会对应多个翻译和解释,这也是与字典集合特性对应的。

    创建字典

    字典类型是dict,创建字典可以使用dict()函数,或者用大括号{}将“键:值”对包裹,“键:值”对之间用逗号分隔。

    在Python Shell中运行示例代码如下:

    >>> dict1 = {102: '张三', 105: '李四', 109: '王五'} ①
    >>> len(dict1)
    3
    >>> dict1
    {102: '张三', 105: '李四', 109: '王五'}
    >>> type(dict1)
    <class 'dict'>
    >>> dict1  = {}
    >>> dict1
    {}
    >>> dict({102: '张三', 105: '李四', 109: '王五'})  ②
    {102: '张三', 105: '李四', 109: '王五'}
    >>> dict(((102, '张三'), (105, '李四'), (109, '王五'))) ③
    {102: '张三', 105: '李四', 109: '王五'}
    >>> dict([(102, '张三'), (105, '李四'), (109, '王五')]) ④
    {102: '张三', 105: '李四', 109: '王五'}
    >>> t1 = (102, '张三')
    >>> t2 = (105, '李四')
    >>> t3 = (109, '王五')
    >>> t = (t1, t2, t3) 
    >>> dict(t) ⑤
    {102: '张三', 105: '李四', 109: '王五'}
    >>> list1 = [t1, t2, t3] 
    >>> dict(list1) ⑥
    {102: '张三', 105: '李四', 109: '王五'}
    >>> dict(zip([102, 105, 109], ['张三', '李四', '王五']))  ⑦
    {102: '张三', 105: '李四', 109: '王五'}
    

    上述代码第①行是使用大括号“键:值”对创建字典,这是最简单的创建字典方式了,那么创建一个空字典表达式是{}。获得字典长度(键值对个数)也是使用len()函数。

    代码第②行、第③行、第④行、第⑤行和第⑥行都用dict()函数创建字典。代码第②行dict()函数参数是另外一个字典{102:
    '张三', 105: '李四', 109: '王五'},使用这种方式不如直接使用大括号“键:值”。

    代码第③行和第⑤行参数是一个元组,这个元组中要包含三个只有两个元素的元组,创建过程参考如图9-6所示。代码第④行和第⑥行参数是一个列表,这个列表中包含三个只有两个元素的元组。

    图9-6 创建字典

    代码第⑦行是使用zip()函数,zip()函数将两个可迭代对象打包成元组,在创建字典时,可迭代对象元组,需要两个可迭代对象,第一个是键([102,
    105, 109]),第二个是值(['张三', '李四',
    '王五']),他们包含的元素个数相同,并且一一对应。

    注意 使用dict()函数创建字典还可以使用一种key=value形式参数,语法如下:

    dict(key1=value1, key2=value2, key3=value3...)

    key=value形式只能创建键是字符串类型的字典,使用时需要省略包裹字符串的引号(包括双引号或单引号)。在Python
    Shell中运行示例代码如下:

    >>> dict(102 = '张三', 105 = '李四', 109 = '王五') ①

    SyntaxError: keyword can't be an expression

    >>> dict('102' = '张三', '105' = '李四', '109' = '王五') ②

    SyntaxError: keyword can't be an expression

    >>> dict(S102 = '张三', S105 = '李四', S109 = '王五') ③

    {'S102': '张三', 'S105': '李四', 'S109': '王五'}

    代码第①行试图通过上述dict()函数创建键是整数类型的字典,结果会发生错误。代码第②行是试图使用字符串作为键创建字典,但是该dict()函数需要省略字符串键的引号,因此会发生错误。需要注意本例中键是由数字构成的字符串,他们很特殊如果省略包裹他们的引号,那么他们会表示为数字,使用该dict()函数是不允许的,所以此时的键不会识别字符串类型。代码第③行的键是在数字前面加S字母,这样不会识别为字符串类型。

    修改字典

    字典可以被修改,但都是针对键和值同时操作,修改字典包括添加、替换和删除“键:值”对。

    在Python Shell中运行示例代码如下:

    >>> dict1 = {102: '张三', 105: '李四', 109: '王五'} 
    >>> dict1[109] ①
    '王五'
    >>> dict1[110] = '董六' ②
    >>> dict1
    {102: '张三', 105: '李四', 109: '王五', 110: '董六'}
    >>> dict1[109] = '张三' ③
    >>> dict1
    {102: '张三', 105: '李四', 109: '张三', 110: '董六'}
    >>> del dict1[109] ④
    >>> dict1
    {102: '张三', 105: '李四', 110: '董六'}
    >>> dict1.pop(105)
    '李四'
    >>> dict1
    {102: '张三', 110: '董六'}
    >>> dict1.pop(105, '董六') ⑤
    '董六'
    >>> dict1.popitem() ⑥
    (110, '董六')
    >>> dict1
    {102: '张三'}
    

    访问字典中元素可通过下标实现,下标参数是键,返回对应的值,代码第①行是dict1[109]是取出字典dict1中键为109的值。字典下标访问元素也可以在赋值符号(=)左边,代码第②行是字典110键赋值,注意此时字典dict1中没有110键,那么这样的操作会添加110:
    '董六'键值对。如果键存在那么会替换对应的值,代码第③行会将键109对应的值替换为'张三',虽然此时值视图中已经有'张三'了,但仍然可以添加,这说明值是可以重复的。

    代码第④行是删除109键对应的值,注意del是语句不是函数。使用del语句删除键值对时,如果键不存在会抛出错误。

    如果喜欢使用方法删除元素,可以使用字典的pop(key[,
    default])和popitem()方法。pop(key[,
    default])方法删除键值对,如果键不存在则返回默认值(default),见代码第⑤行是105键不存在返回默认值'董六'。popitem()方法删除任意键值对,返回删除的键值对,构成的元组,上述代码第⑥行删除了一个键值对,返回一个元组对象(110,
    '董六')。

    访问字典

    字典还一些方法用来访问它的键或值,这些方法如下:

    • get(key[, default])。通过键返回值,如果键不存在返回默认值。

    • items()。返回字典的所有键值对。

    • keys()。返回字典键视图。

    • values()。返回字典值视图。

    在Python Shell中运行示例代码如下:

    >>> dict1 = {102: '张三', 105: '李四', 109: '王五'}
    >>> dict1.get(105)  ①
    '李四'
    >>> dict1.get(101)  ②
    >>> dict1.get(101, '董六') ③
    '董六'
    >>> dict1.items() 
    dict_items([(102, '张三'), (105, '李四'), (109, '王五')])
    >>> dict1.keys() 
    dict_keys([102, 105, 109])
    >>> dict1.values() 
    dict_values(['张三', '李四', '王五'])
    

    上述代码第①行是通过get()方法返回105键对应的值,如果没有键对应的值,而且还没有为get()方法提供默认值,则不会有返回值,见代码第②行。代码第③行是提供了返回值。

    在访问字典时,也可以使用in和not in运算符,但是需要注意的是in和not
    in运算符只测试键视图中进行。在Python Shell中运行示例代码如下:

    >>> student_dict = {'102': '张三', '105': '李四', '109': '王五'}
    >>> 102 in dict1
    True
    >>> '李四' in dict1
    False
    

    遍历字典

    字典遍历也是字典的重要操作。与集合不同,字典有两个视图,因此遍历过程可以只遍历值视图,也可以只遍历键视图,也可以同时遍历。这些遍历过程都是通过for循环实现的。

    示例代码如下:

    # coding=utf-8
    # 代码文件:chapter9/ch9.4.4.py
    
    student_dict = {102: '张三', 105: '李四', 109: '王五'}  
    
    print('---遍历键---')
    for student_id in student_dict.keys():  ①
        print('学号:' + str(student_id))
    
    print('---遍历值---')
    for student_name in student_dict.values(): ②
        print('学生:' + student_name)
    
    print('---遍历键:值---')
    for student_id, student_name in student_dict.items(): ③ 
        print('学号:{0} - 学生:{1}'.format(student_id, student_name))
    

    输出结果如下:

    ---遍历键---
    学号:102
    学号:105
    学号:109
    ---遍历值---
    学生:张三
    学生:李四
    学生:王五
    ---遍历键:值---
    学号:102 - 学生:张三
    学号:105 - 学生:李四
    学号:109 - 学生:王五
    

    上述代码第③行遍历字典的键值对,items()方法返回是键值对元组序列,student_id,
    student_name是从元组拆包出来的两个变量。

    字典推导式

    因为字典包含了键和值两个不同的结构,因此字典推导式结果可以非常灵活。字典推导示例代码如下:

    # coding=utf-8
    # 代码文件:chapter9/ch9.4.5.py
    
    input_dict = {'one': 1, 'two': 2, 'three': 3, 'four': 4} 
    
    output_dict = {k: v for k, v in input_dict.items() if v % 2 == 0} ①
    print(output_dict)
    
    keys = [k for k, v in input_dict.items() if v % 2 == 0]  ②
    print(keys)
    

    输出结构如下:

    {'two': 2, 'four': 4}
    ['two', 'four']
    

    上述代码第①行是字典推导式,注意输入结构不能直接使用字典,因为字典不是序列,可以通过字典的item()方法返回字典中键值对序列。代码第②行是字典推导式,但只返回键结构。

    本章小结

    本章介绍了Python中的几种数据结构。其中包括序列、元组、集合和字典,了解序列的特点,清楚序列包括哪些结构。然后详细介绍了元组、集合和字典。

    配套视频

    http://www.zhijieketang.com/classroom/10/courses

    配套源代码

    http://www.zhijieketang.com/group/8

    纸质版电商

    京东:https://item.jd.com/12468732.html
    当当:http://product.dangdang.com/25574315.html

    作者微博:@tony_关东升
    邮箱:eorient@sina.com
    智捷课堂微信公共号:zhijieketang
    Python读者服务QQ群:565736812


    1. 可迭代(iterable),是指它的成员能返回一次的对象。

    相关文章

      网友评论

        本文标题:《Python从小白到大牛》第9章 数据结构

        本文链接:https://www.haomeiwen.com/subject/wchrjftx.html