学习Python编程基础学习笔记(4.Python数据结构)

目录

一:序列类型

1.1列表结构类型 (List)

1.1.1用列表实现堆栈

1.1.2用列表实现队列

1.1.3del 语句

1.2元组(Tuple)

二:集合类型

2.1集合(Set)

三:映射类型

3.1字典(dict)

四:其他类型数据类型

4.1容器数据类型( collections)

4.1.1namedtuple() 命名元组的工厂函数

4.1.2collections.deque 对象

4.1.3collections.ChainMap 对象

4.1.4collections.Counter 字典的子类

4.1.5collections.OrderedDict 对象

4.1.6defaultdict 对象

4.1.7UserDict 对象

4.1.8UserList 对象

4.1.9UserString 对象


​​​​​​​​​​​​​​

        之前介绍的数字类型如:整数类型、浮点数类型和复数类型,这些都能表示一个数据,这种表示单一数据的类型叫做基本数据类型,然而实际情况中存在大量同时处理多个数据的情况,这就需要将多个数据有效组织起来并统一表示,这种能够表示多个数据的类型称为组合数据类型

        序列类型是一个元素向量,元素之间存在先后关系,通过序号访问,元素之间不排他。 

        集合类型是一个元素集合,元素之间无序,相同元素在集合中唯一存在。

        映射类型是“键-值”数据项的组合,每个元素是一个键值对,表示为(key,value)。

一:序列类型

        这种类型的数据,使用相同的索引体系,即正向递增序号和反向递减序号。

         序列类型有12个通用的操作符和函数。

操作符描述
x  in s如果x是s的元素,返回True,否则返回False
x not in s如果x不是s的元素,返回True,否则返回False
s+t连接s和t
s*n或n*s将序列s复制n次
s[i]索引,返回序列的第i个元素
s[i:j]分片,返回包含序列s第i到j个元素的子序列(不包含第j个元素)
s[i:j:k]步骤分片,返回包含序列s第i到j个元素一k为步数的子序列
lens(s)序列s的元素个数
min(s)序列s中的最小元素
max(s)序列s中的最大元素
s.index(x[,i[,j]])序列s中从i开始到j位置中第一次出现元素x的位置
s.count(x)序列s中出现x的中次数

生成

range()创建整数列表
range()可以帮助我们非常方便的创建整数列表,这在开发中及其有用。语法格式为:
range([start],end ,[step])
start 参数:可选,表示起始数字。默认是 0
end   参数:必选,表示结尾数字。
step  参数:可选,表示步长,默认为 1

e = list(range(0,10,2))
print(e)      #结果:[0, 2, 4, 6, 8]

f = list(range(10,0,-1))
print(f)      #结果:[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

g = list(range(-10,-30,-2))
print(g)      #结果:[-10, -12, -14, -16, -18, -20, -22, -24, -26, -28]

1.1列表结构类型 (List)

        在之前的章节我们已经了解过 List 结构:

list1 = [1, 2, 3, 4]
#list1 只有数字

list2 = [1, 2, "a", "b"]
#list2 包含数字和字符串复合内容

list3 = [list1, list2]
#list3 在列表中包含列表

        列表中的列表是Python中最强大的工具之一。列表可以包含字符串、整数以及对象等数据类型。列表还可用于实现堆栈和队列。

        列表是可变的,声明后仍然可以修改。

        示例:

list1 = []
# 声明一个空列表

print(list1) # 输出空列表 []

list1.append("a")
# 在列表最后位置添加元素

list1.insert(0, "b")
# 在指定位置插入元素

        列表特有的函数和操作方法(下次讲) 

列表应用 

1.1.1用列表实现堆栈

        使用列表方法实现堆栈非常容易,最后插入的最先取出(“后进先出”)。把元素添加到堆栈的顶端,使用 append() 。从堆栈顶部取出元素,使用 pop() ,不用指定索引。例如:

stack = [3, 4, 5]
stack.append(6)
stack.append(7)
print(stack)
# 输出 [3, 4, 5, 6, 7]

print(stack.pop())
# 输出 7

print(stack)
# 输出 [3, 4, 5, 6]

1.1.2用列表实现队列

        列表也可以用作队列,最先加入的元素,最先取出(“先进先出”);然而,列表作为队列的效率很低。因为,在列表末尾添加和删除元素非常快,在列表开头插入或移除元素却很慢(因为所有其他元素都必须移动一位)。

        实现队列最好用 collections.deque ,可以快速从两端添加或删除元素。例如:

from collections import deque
queue = deque(["Eric", "John", "Michael"])
queue.append("Terry")           # 在最后添加元素
queue.append("Graham")          # 在最后添加元素
print(queue.popleft())                 # 弹出第一个元素 
# 输出 'Eric'
print(queue.popleft())                 # 弹出第一个元素
# 输出 'John'

        列表推导式

        列表推导式创建列表的方式更简洁。常见的用法为,对序列或可迭代对象中的每个元素应用某种操作,用生成的结果创建新的列表;或用满足特定条件的元素创建子序列。

        例如,创建平方值的列表:

squares = []
for x in range(10):
    squares.append(x**2)

print(squares)
# 输出 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

        这段代码创建(或覆盖)变量 x,该变量在循环结束后仍然存在。下述方法可以无副作用地计算平方列表:

squares = list(map(lambda x: x**2, range(10)))

        等价于:

squares = [x**2 for x in range(10)]

   map(function, iterable) 函数接受两个参数,第一个参数是函数,返回处理过的值,第二个参数是可迭代,返回Map类型。

        示例:

def foo(n: int):
    return n ** n

print(list(map(foo, [1,2,3,4])))
# [1, 4, 27, 256]

         参考:内置函数 — Python 3.9.7 文档

        此时写法变量 x 只是在推导式中有效,这种写法更简洁、易读。

        列表推导式的方括号内包含以下内容:一个表达式,后面是一个 for 子句,然后,是零个或多个 for 或 if 子句。结果是由表达式依据 for 和 if 子句求值计算而得出一个新列表。 举例来说,以下列表推导式将两个列表中不相等的元素组合起来:

print([(x, y) for x in [1,2,3] for y in [3,1,4] if x != y])
# [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

        等价于:

combs = []
for x in [1,2,3]:
    for y in [3,1,4]:
        if x != y:
            combs.append((x, y))


print(combs)

        上面两段代码中,for 和 if 的顺序相同。

        表达式是元组(例如上例的 (x, y))时,必须加上括号:

print([(x, x**2) for x in range(6)])

# [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]

        嵌套的列表推导式

        列表推导式中的初始表达式可以是任何表达式,甚至可以是另一个列表推导式。

下面这个 3x4 矩阵,由 3 个长度为 4 的列表组成:

matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
]

# 下面的列表推导式可以转置行列:

print([[row[i] for row in matrix] for i in range(4)])

# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

# 如上节所示,嵌套的列表推导式基于其后的 for 求值,所以这个例子等价于:
transposed = []
for i in range(4):
    transposed.append([row[i] for row in matrix])

print(transposed)
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

# 反过来说,也等价于:
transposed = []
for i in range(4):
    # the following 3 lines implement the nested listcomp
    transposed_row = []
    for row in matrix:
        transposed_row.append(row[i])
    transposed.append(transposed_row)

print(transposed)
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

# 实际应用中,最好用内置函数替代复杂的流程语句。此时,zip() 函数更好用:
print(list(zip(*matrix)))

        查看 zip()

        表达式中星号的详细说明,参见 解包实参列表 。

1.1.3del 语句

   del 语句按索引,而不是值从列表中移除元素。与返回值的 pop() 方法不同, del 语句也可以从列表中移除切片,或清空整个列表(之前是将空列表赋值给切片)。 例如:

a = [-1, 1, 66.25, 333, 333, 1234.5]
del a[0]
print(a)
[1, 66.25, 333, 333, 1234.5]
del a[2:4]
print(a)
[1, 66.25, 1234.5]
del a[:]
print(a)
[]

       del 也可以用来删除整个变量:

del a

        此后,再引用 a 就会报错(直到为它赋与另一个值)。后文会介绍 del 的其他用法。

1.2元组(Tuple)

        我们已经介绍过两种序列类型的数据类型:列表和字符串(我没讲,诶,就是玩),这两种数据类型均可以进行索引和切片操作。

        本节介绍另一种标准序列类型:元组,元组由多个用逗号隔开的值组成。

        示例:

tp = "字符串", "列表", "元组"
print(tp[0])
# 输出 "字符串"

# 元组嵌套
u = tp, (1, 2, 3, 4, 5)
print(u)
# 输出:(('字符串', '列表', "元组"), (1, 2, 3, 4, 5))

        元组一旦创建就不能被修改。元组不支持按索引修改,示例:

tp = "字符串", "列表", "元组"
tp[0] = "尝试修改"
# 解释器抛除类型错误:TypeError: 'tuple' object does not support item assignment

        Python解释器输出时,元组都要由圆括号标注,这样才能正确地解释嵌套元组。输入时,圆括号可有可无,不过经常是必须的(如果元组是更大的表达式的一部分)。不允许为元组中的单个元素赋值,当然,可以创建含列表等可变对象的元组。

        虽然,元组与列表很像,但使用场景不同,用途也不同。元组是 immutable (不可变的),一般可包含异质元素序列,通过解包(见本节下文)或索引访问(如果是 namedtuples,可以属性访问)。列表是 mutable (可变的),列表元素一般为同质类型,可迭代访问。

        构造 0 个或 1 个元素的元组比较特殊:为了适应这种情况,对句法有一些额外的改变。用一对空圆括号就可以创建空元组;只有一个元素的元组可以通过在这个元素后添加逗号来构建(圆括号里只有一个值的话不够明确)。丑陋,但是有效。例如:

empty = ()
print(len(empty))
# 0

singleton = 'hello',    # <-- 必须加上尾部的 , 符号才是元组,否则解释器认为是字符串
print(len(singleton))
# 1

print(singleton)
('hello',)

        解包

        表达式 tp = "字符串", "列表", "元组" 可以看作是元组的打包,值 "字符串", "列表", "元组" 一起被打包进 tp 变量中。

        元组和列表还可以进行逆向解包操作,示例:

tp = "字符串", "列表", "元组"

z, l, y = tp

print(z) # 输出 "字符串"
print(l) # 输出 "列表"

        称之为 序列解包 也是妥妥的,适用于右侧的任何序列。序列解包时,左侧变量与右侧序列元素的数量应相等。注意,多重赋值其实只是元组打包和序列解包的组合

        请自行尝试list结构解包操作

二:集合类型

        集合类型操作符(下来再写)20210808

操作符描述
S - T 或 S.difference(T)返回一个新集合,包括在集合S中但不在集合T中的元素
S -= T 或 S.difference_update(T)更新集合S,包括在集合S中但不在集合T中的元素
S & T 或 S.intersection(T)返回一个新集合,包括同时在集合S和集合T中的元素
S &= T 或 S.intersection_update(T)更新集合S,包括同时在集合S和集合T中的元素
S^T 或 S.symmetric_difference(T)返回一个新集合,包括同时在集合S和集合T中的元素,但不包括同时在其中的元素
S=^T 或 S.symmetric_difference_update(T)更新集合S,包括同时在集合S和集合T中的元素,但不包括同时在其中的元素
S|T 或S.union(T)返回一个新集合,包括同时在集合S和集合T中的所有元素
S=|T 或S.update(T)更新集合S,包括同时在集合S和集合T中的所有元素
S<=T 或S.issubset(T)

如果S与T相同或S是T的子集,返回True,否则返回False,可以用S<T判断S是否是T的真子集

S>=T 或S.issuperset(T)如果S与T相同或S是T的超集,返回True,否则返回False,可以用S>T判断S是否是T的真超集

         上述操作符表达了集合类型的4种基本操作:交集(&)、并集(|)、差集(-)、

补集(^),操作逻辑与数字定义相同,如下图:

        集合类型有10个操作函数或方法,如下表所示:

操作函数或方法描述
S.add(x)如果数据项x不在集合S中,将x增加到s
S.clear()移除S中的所有数据项
S.copy()返回集合S的一个副本
S.pop()随机返回集合S中的一个元素,如果S为空,产生KeyError异常
S.discard(x)如果x在集合S中,移除该元素;如果x不在集合S中,不报错
S.remove(x)如果x在集合S中,移除该元素;如果x不在集合S中,产生KeyError异常
S.isdisjoint(x)如果集合S与T没有相同元素,返回True
len(S)返回集合S的元素个数
x in S如果x是集合S的元素,返回True,否则返回False
x not in S如果x不是集合S的元素,返回True,否则返回False

         集合类型常用于3个场景:成员关系检测、元素去重和删除数据项。

2.1集合(Set)

        集合是由不重复元素组成的无序容器。基本用法包括成员检测、消除重复元素。集合对象支持合集、交集、差集、对称差分等数学运算。

        创建集合用花括号或 set() 函数。注意,创建空集合只能用 set(),不能用 {},{} 创建的是空字典,下一小节介绍数据结构:字典。

        示例:

basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket) # 输出结果中重复元素已经被删除
# 输出 {'orange', 'banana', 'pear', 'apple'}

print('orange' in basket)                 # fast membership testing
# 输出 True
print('crabgrass' in basket)
# 输出 False

# Demonstrate set operations on unique letters from two words

a = set('abracadabra')
b = set('alacazam')
print(a)
# 输出 {'a', 'r', 'b', 'c', 'd'}, 输出结果值包含一个a字母

a - b # 计算两个set结构的差
# 输出 {'r', 'd', 'b'}

a | b # 合并两个set
# 输出 {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}


a & b # 计算两个set的交集
# 输出 {'a', 'c'}


a ^ b # 计算对称差集
# 输出 {'r', 'd', 'b', 'm', 'z', 'l'}

三:映射类型

        字典类型的函数和方法(下次讲​​​​​​​)

3.1字典(dict)

        字典也是一种常用的 Python 內置数据类型。其他语言可能把字典称为联合内存 或联合数组。与以连续整数为索引的序列不同,字典以关键字为索引,关键字通常是字符串或数字,也可以是其他任意不可变类型。只包含字符串、数字、元组的元组,也可以用作关键字。但如果元组直接或间接地包含了可变对象,就不能用作关键字。列表不能当关键字,因为列表可以用索引、切片、append() 、extend() 等方法修改。

        可以把字典理解为键值对的集合,但字典的键必须是唯一的。花括号 {} 用于创建空字典。另一种初始化字典的方式是,在花括号里输入逗号分隔的键值对,这也是字典的输出方式。

        字典的主要用途是通过关键字存储、提取值。用 del 可以删除键值对。用已存在的关键字存储值,与该关键字关联的旧值会被取代。通过不存在的键提取值,则会报错。

        对字典执行 list(d) 操作,返回该字典中所有键的列表,按插入次序排列(如需排序,请使用 sorted(d))。检查字典里是否存在某个键,使用关键字 in 。

        示例:

tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127
print(tel)
# 输出 {'jack': 4098, 'sape': 4139, 'guido': 4127}

print(tel['jack'])
# 输出 4098
del tel['sape'] # 使用 del 删除元素
tel['irv'] = 4127
print(tel)
# 输出 {'jack': 4098, 'guido': 4127, 'irv': 4127}

print(list(tel)) # 将字段转换为列表
# 输出 ['jack', 'guido', 'irv']

print(sorted(tel)) # 排序
# 输出 ['guido', 'irv', 'jack']


print('guido' in tel)
# 输出 True

print('jack' not in tel)
# 输出 False

        dict() 构造函数可以直接用键值对序列创建字典:

foo = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
print(foo)
# 输出 {'sape': 4139, 'guido': 4127, 'jack': 4098}

        字典推导式可以用任意键值表达式创建字典:

foo = {x: x**2 for x in (2, 4, 6)}
print(foo)
# 输出 {2: 4, 4: 16, 6: 36}

        关键字是比较简单的字符串时,直接用关键字参数指定键值对更便捷:

foo = dict(sape=4139, guido=4127, jack=4098)
print(foo)
# 输出 {'sape': 4139, 'guido': 4127, 'jack': 4098}

四:其他类型数据类型

4.1容器数据类型( collections)

        collections 不是Python语言层面的数据类型,collections是Python内置的一个模块。

import collections
# 导入 collections 模块

        这个模块实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择。

函数释义
namedtuple()创建命名元组子类的工厂函数
deque类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
ChainMap类似字典(dict)的容器类,将多个映射集合到一个视图里面
Counter字典的子类,提供了可哈希对象的计数功能
OrderedDict字典的子类,保存了他们被添加的顺序
defaultdict字典的子类,提供了一个工厂函数,为字典查询提供一个默认值
UserDict封装了字典对象,简化了字典子类化
UserList封装了列表对象,简化了列表子类化
UserString封装了列表对象,简化了字符串子类化

4.1.1namedtuple() 命名元组的工厂函数

(collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None))

        namedtuple() 函数,接受5个参数:

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

typename

        返回一个新的元组子类,名为 typename 。这个新的子类用于创建类元组的对象,可以通过字段名来获取属性值,同样也可以通过索引和迭代获取值。子类实例同样有文档字符串(类名和字段名)另外一个有用的 repr() 方法,以 name=value 格式列明了元组内容。

field_names

        field_names 是一个像 ['x', 'y'] 一样的字符串序列。另外 field_names 可以是一个纯字符串,用空白或逗号分隔开元素名,比如 ‘x y’ 或者 ‘x, y’ 。

        任何有效的Python 标识符都可以作为字段名,除了下划线开头的那些。有效标识符由字母,数字,下划线组成,但首字母不能是数字或下划线,另外不能是关键词 keyword 比如 class, for, return, global, pass, 或 raise 。

rename

        如果 rename 为真, 无效字段名会自动转换成位置名。比如 ['abc', 'def', 'ghi', 'abc'] 转换成 ['abc', '_1', 'ghi', '_3'] , 消除关键词 def 和重复字段名 abc 。

defaults

        defaults 可以为 None 或者是一个默认值的 iterable 。如果一个默认值域必须跟其他没有默认值的域在一起出现,defaults 就应用到最右边的参数。比如如果域名 ['x', 'y', 'z'] 和默认值 (1, 2) ,那么 x 就必须指定一个参数值 ,y 默认值 1 , z 默认值 2 。

module

        如果 module 值有定义,命名元组的 module 属性值就被设置。

   namedtuple() 返回一个带有命名字段的子类元组.

        示例:

from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p = Point(11, y=22) # 分别使用位置和关键词参数为元组赋值
print(p[0] + p[1]) # 像普通元组 tuple 一样使用索引
# 输出 33

x, y = p # 解包操作
print((x, y))
# 输出 (11, 22)

print(p.x + p.y) # 使用名称访问字段
# 输出 33


print(p.__repr__()) # 等效 print(p) 以 name=value 格式列明了元组内容
# 输出 Point(x=11, y=22)

        namedtuple 对象还有其他有用的方法,请参考 collections.namedtuple 。

4.1.2collections.deque 对象

(class collections.deque([iterable[, maxlen]]))     

        deque() 函数返回一个新的双向队列对象,从左到右初始化(用方法 append()) ,从 iterable (迭代对象) 数据创建。如果 iterable 没有指定,新队列为空。

  deque([iterable[, maxlen]]) 函数接受2个参数,iterable 接受一个可迭代对象,maxlen 用来限制创建队列的长度,如果不限制可以创建无限长度队列。

        一旦限定长度的deque满了,当新项加入时,同样数量的项就从另一端弹出。限定长度deque提供类似Unix filter tail 的功能。它们同样可以用与追踪最近的交换和其他数据池活动。

        示例:

from collections import deque

d = deque('abc')

d.append("d")
# 在最后压入元素
d.appendleft("0")
# 在开始位置押入元素

for elem in d:
    print(elem.upper())
    # 使用 upper() 函数将小写字母转为大写字母

双向队列(deque)对象支持以下方法:

        append(x) 添加 x 到右端。

        appendleft(x) 添加 x 到左端。

        clear() 移除所有元素,使其长度为0.

        copy() 创建一份浅拷贝。

3.5 新版功能.

        count(x) 计算 deque 中元素等于 x 的个数。

3.2 新版功能.

        extend(iterable) 扩展deque的右侧,通过添加iterable参数中的元素。

        extendleft(iterable) 扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。

        index(x[, start[, stop]]) 返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发 ValueError。

3.5 新版功能.

        insert(i, x) 在位置 i 插入 x 。

        如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError。

3.5 新版功能.

        pop() 移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError。

        popleft() 移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError。

        remove(value) 移除找到的第一个 value。 如果没有的话就引发 ValueError。

        reverse() 将deque逆序排列。返回 None 。

3.2 新版功能.

        rotate(n=1) 向右循环移动 n 步。 如果 n 是负数,就向左循环。

        如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft()) 。

        Deque对象同样提供了一个只读属性:

        maxlen Deque的最大尺寸,如果没有限定的话就是 None 。

3.1 新版功能.

        除了以上操作,deque 还支持迭代、封存、len(d)、reversed(d)、copy.copy(d)、copy.deepcopy(d)、成员检测运算符 in 以及下标引用例如通过 d[0] 访问首个元素等。 索引访问在两端的复杂度均为 O(1) 但在中间则会低至 O(n)。 如需快速随机访问,请改用列表。

        更多示例见代码示例文件: code/datastructures/python_collections.py

4.1.3collections.ChainMap 对象

class collections.ChainMap(*maps)

ChainMap 是 Python 3.3 新版功能

        一个 ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update() 要快很多。

        这个类可以用于模拟嵌套作用域,并且在模版化的时候比较有用。

        一个 ChainMap 将多个字典或者其他映射组合在一起,创建一个单独的可更新的视图。 如果没有 maps 被指定,就提供一个默认的空字典,这样一个新链至少有一个映射。

        底层映射被存储在一个列表中。这个列表是公开的,可以通过 maps 属性存取和更新。没有其他的状态。

        搜索查询底层映射,直到一个键被找到。不同的是,写,更新和删除只操作第一个映射。

        一个 ChainMap 通过引用合并底层映射。 所以,如果一个底层映射更新了,这些更改会反映到 ChainMap 。

        支持所有常用字典方法。另外还有一个 maps 属性(attribute),一个创建子上下文的方法(method), 一个存取它们首个映射的属性(property):

  • maps

    一个可以更新的映射列表。这个列表是按照第一次搜索到最后一次搜索的顺序组织的。它是仅有的存储状态,可以被修改。列表最少包含一个映射。

  • new_child(m=None)

    返回一个新的 ChainMap 类,包含了一个新映射(map),后面跟随当前实例的全部映射(map)。如果 m 被指定,它就成为不同新的实例,就是在所有映射前加上 m,如果没有指定,就加上一个空字典,这样的话一个 d.new_child() 调用等价于 ChainMap({}, *d.maps) 。这个方法用于创建子上下文,不改变任何父映射的值。在 3.4 版更改: 添加了 m 可选参数。

  • parents

    属性返回一个新的 ChainMap 包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射。 使用的场景类似在 nested scopes 嵌套作用域中使用 nonlocal 关键词。用例也可以类比内建函数 super() 。一个 d.parents 的引用等价于 ChainMap(*d.maps[1:]) 。 

        注意,一个 ChainMap() 的迭代顺序是通过扫描最后的映射来确定的:

from collections import ChainMap

baseline = {'music': 'bach', 'art': 'rembrandt'}
adjustments = {'art': 'van gogh', 'opera': 'carmen'}
list(ChainMap(adjustments, baseline))
# ['music', 'art', 'opera']

        这给出了与 dict.update() 调用序列相同的顺序,从最后一个映射开始:

baseline = {'music': 'bach', 'art': 'rembrandt'}
adjustments = {'art': 'van gogh', 'opera': 'carmen'}

combined = baseline.copy()
combined.update(adjustments)
print(list(combined))
# ['music', 'art', 'opera']

        在 3.9 版更改: 增加了对 | 和 |= 运算符的支持,相关说明见 PEP 584

        更多 ChainMap 例子和方法

4.1.4collections.Counter 字典的子类

class collections.Counter([iterable-or-mapping])

        一个 Counter 是一个 dict 的子类,用于计数可哈希对象。它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数。 Counter 类有点像其他语言中的 bags或multisets。

        元素从一个 iterable 被计数或从其他的 mapping (or counter)初始化:

from collections import Counter

c = Counter()                           # a new, empty counter
c = Counter('gallahad')                 # a new counter from an iterable
c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
c = Counter(cats=4, dogs=8)             # a new counter from keyword args

        Counter对象有一个字典接口,如果引用的键没有任何记录,就返回一个0,而不是弹出一个 KeyError :

from collections import Counter

c = Counter(['eggs', 'ham'])
print(c['bacon'])                              # count of a missing element is zero
# 0

        设置一个计数为0不会从计数器中移去一个元素。使用 del 来删除它:

from collections import Counter

c = Counter(['eggs', 'ham'])
c['sausage'] = 0                        # counter entry with a zero count
del c['sausage']                        # del actually removes the entry

        Python 3.1 新版功能.

        在 3.7 版更改: 作为 dict 的子类,Counter 继承了记住插入顺序的功能。 Counter 对象进行数学运算时同样会保持顺序。 结果会先按每个元素在运算符左边的出现时间排序,然后再按其在运算符右边的出现时间排序。

计数器对象除了字典方法以外,还提供了三个其他的方法:

通常字典方法都可用于 Counter 对象,除了有两个方法工作方式与字典并不相同。

  • fromkeys(iterable)

    这个类方法没有在 Counter 中实现。

  • update([iterable-or-mapping])

    从 迭代对象 计数元素或者 从另一个 映射对象 (或计数器) 添加。 像 dict.update() 但是是加上,而不是替换。另外,迭代对象 应该是序列元素,而不是一个 (key, value) 对。

4.1.5collections.OrderedDict 对象

有序词典就像常规词典一样,但有一些与排序操作相关的额外功能。由于内置的 dict 类获得了记住插入顺序的能力(在 Python 3.7 中保证了这种新行为),它们变得不那么重要了。

一些与 dict 的不同仍然存在:

  • 常规的 dict 被设计为非常擅长映射操作。 跟踪插入顺序是次要的。
  • OrderedDict 旨在擅长重新排序操作。 空间效率、迭代速度和更新操作的性能是次要的。
  • 算法上, OrderedDict 可以比 dict 更好地处理频繁的重新排序操作。 这使其适用于跟踪最近的访问(例如在 LRU cache 中)。
  • 对于 OrderedDict ,相等操作检查匹配顺序。
  • OrderedDict 类的 popitem() 方法有不同的签名。它接受一个可选参数来指定弹出哪个元素。
  • OrderedDict 类有一个 move_to_end() 方法,可以有效地将元素移动到任一端。
  • Python 3.8之前, dict 缺少 __reversed__() 方法。

        class collections.``OrderedDict([items]) 

返回一个 dict 子类的实例,它具有专门用于重新排列字典顺序的方法。3.1 新版功能.popitem(last=True)有序字典的 popitem() 方法移除并返回一个 (key, value) 键值对。 如果 last 值为真,则按 LIFO 后进先出的顺序返回键值对,否则就按 FIFO 先进先出的顺序返回键值对。move_to_end(keylast=True)将现有 key 移动到有序字典的任一端。 如果 last 为真值(默认)则将元素移至末尾;如果 last 为假值则将元素移至开头。如果 key 不存在则会触发 KeyError:>>>>>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d.keys()) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d.keys()) 'bacde' 3.2 新版功能.

相对于通常的映射方法,有序字典还另外提供了逆序迭代的支持,通过 reversed() 。

OrderedDict 之间的相等测试是顺序敏感的,实现为 list(od1.items())==list(od2.items()) 。 OrderedDict 对象和其他的 Mapping 的相等测试,是顺序敏感的字典测试。这允许 OrderedDict 替换为任何字典可以使用的场所。

在 3.5 版更改: OrderedDict 的项(item),键(key)和值(value) 视图 现在支持逆序迭代,通过 reversed() 。

在 3.6 版更改: PEP 468 赞成将关键词参数的顺序保留, 通过传递给 OrderedDict 构造器和它的 update() 方法。

在 3.9 版更改: 增加了合并 (|) 与更新 (|=) 运算符,相关说明见 PEP 584

4.1.6defaultdict 对象

class collections.``defaultdict([default_factory[, ]])

返回一个新的类似字典的对象。 defaultdict 是内置 dict 类的子类。它重载了一个方法并添加了一个可写的实例变量。其余的功能与 dict 类相同,此处不再重复说明。

本对象包含一个名为 default_factory 的属性,构造时,第一个参数用于为该属性提供初始值,默认为 None。所有其他参数(包括关键字参数)都相当于传递给 dict 的构造函数。

defaultdict 对象除了支持标准 dict 的操作,还支持以下方法作为扩展:

  • __missing__(key)

    如果 default_factory 属性为 None,则调用本方法会抛出 KeyError 异常,附带参数 key。如果 default_factory 不为 None,则它会被(不带参数地)调用来为 key 提供一个默认值,这个值和 key 作为一对键值对被插入到字典中,并作为本方法的返回值返回。如果调用 default_factory 时抛出了异常,这个异常会原封不动地向外层传递。在无法找到所需键值时,本方法会被 dict 中的 __getitem__() 方法调用。无论本方法返回了值还是抛出了异常,都会被 __getitem__() 传递。注意,__missing__() 不会 被 __getitem__() 以外的其他方法调用。意味着 get() 会像正常的 dict 那样返回 None,而不是使用 default_factory

defaultdict 对象支持以下实例变量:

  • default_factory

    本属性由 __missing__() 方法来调用。如果构造对象时提供了第一个参数,则本属性会被初始化成那个参数,如果未提供第一个参数,则本属性为 None

在 3.9 版更改: 增加了合并 (|) 与更新 (|=) 运算符,相关说明见 PEP 584

4.1.7UserDict 对象

UserDict 类是用作字典对象的外包装。对这个类的需求已部分由直接创建 dict 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字典可以作为属性来访问。

  • class collections.``UserDict([initialdata])

    模拟一个字典类。这个实例的内容保存为一个正常字典, 可以通过 UserDict 实例的 data 属性存取。如果提供了 initialdata 值, data 就被初始化为它的内容;注意一个 initialdata 的引用不会被保留作为其他用途。UserDict 实例提供了以下属性作为扩展方法和操作的支持:data一个真实的字典,用于保存 UserDict 类的内容。

4.1.8UserList 对象

这个类封装了列表对象。它是一个有用的基础类,对于你想自定义的类似列表的类,可以继承和覆盖现有的方法,也可以添加新的方法。这样我们可以对列表添加新的行为。

对这个类的需求已部分由直接创建 list 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的列表可以作为属性来访问。

  • class collections.``UserList([list])

    模拟一个列表。这个实例的内容被保存为一个正常列表,通过 UserList 的 data 属性存取。实例内容被初始化为一个 list 的copy,默认为 [] 空列表。 list 可以是迭代对象,比如一个Python列表,或者一个 UserList 对象。UserList 提供了以下属性作为可变序列的方法和操作的扩展:data一个 list 对象用于存储 UserList 的内容。

子类化的要求: UserList 的子类需要提供一个构造器,可以无参数调用,或者一个参数调用。返回一个新序列的列表操作需要创建一个实现类的实例。它假定了构造器可以以一个参数进行调用,这个参数是一个序列对象,作为数据源。

如果一个分离的类不希望依照这个需求,所有的特殊方法就必须重写;请参照源代码进行修改。

4.1.9UserString 对象

UserString 类是用作字符串对象的外包装。对这个类的需求已部分由直接创建 str 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字符串可以作为属性来访问。

  • class collections.``UserString(seq)

    模拟一个字符串对象。这个实例对象的内容保存为一个正常字符串,通过 UserString 的 data 属性存取。实例内容初始化设置为 seq 的copy。seq 参数可以是任何可通过内建 str() 函数转换为字符串的对象。UserString 提供了以下属性作为字符串方法和操作的额外支持:data一个真正的 str 对象用来存放 UserString 类的内容。在 3.5 版更改: 新方法 __getnewargs____rmod__casefoldformat_mapisprintable, 和 maketrans

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

请叫我7plus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值