python字典和集合属于符号_Python字典和集合,与

模块

collections.abc

中的两个抽象基类

Mapping

MutableMapping

dict

和其他类似类型定义了形式接口,然而非抽象映射类型一般不继承自这两个抽象基类,而是拓展

dict

collections.UserDict

。这些抽象基类的主要作用是作为文档,定义构建一个映射类型所需的最基本的接口,还可以搭配

isinstance

运算符判断某个数据是不是广义上的映射类型。

若要自定义一个映射类型,更合适的策略是继承自

collections.UserDict

一、可散列对象

实现了

__hash__()

方法的对象,其散列值在其生命周期中是不变的。同时还需实现

__eq__()

,这样才能进行比较,

如果两个可散列对象是相等的,那么它们的散列值一定相等

。一般来讲用户自定义的类型的对象都是可散列的,且使用它们的

id()

值作为散列值,在比较的时候这些对象都不相等。若一个对象实现了

__eq__

方法,且在方法实现中用到了对象的内部状态,则只有所有内部的状态是不可变的情况下,该对象才是可散列的。

在内置类型中:原子不可变数据类型都是可散列的,而对于原子可变的不可变序列,若其元素均为可散列的,则其可散列。而所有的可变序列,都是不可散列的。

可散列:实现

__hash__()

方法,且该方法返回一个固定不变的、可比较的值

二、字典推导

字典推导从

以键值对作为元素

的可迭代对象中构建出字典。

DIAL_CODES =[

(86,'China'),

(91,'India'),

(1,'United States'),

(55,'Brazil'),

]

{country:code for code,coutry in DIAL_CODES}

>> {

'China':86,

'India':91,

'United States':1,

'Brazil':55,

}

即该可迭代对象中的元素是以对的形式存在的。而对于使用两个

for

子句的推导,不能得到正确形式的字典:

{ x:y for x in range(4) for y in "abcd"}

>> {

0:'d',

1:'d',

2:'d',

3:'d',

}

原因是这种形式的推导实际上是产生:

{

0:'a', 1:'a', 2:'a', 3:'a',

0:'b', 1:'b', 2:'b', 3:'b',

0:'c', 1:'c', 2:'c', 3:'c',

0:'d', 1:'d', 2:'d', 3:'d',

}

而先生成的键值对被后生成的键值对所覆盖。

推而广之,在 Python 中可以用一个映射对象来新建一个映射对象,也可以用包含

(key,value)

元素的可迭代对象初始化映射对象。

三、映射方法

方法

d.clear()

移除字典中所有元素

d.pop(key,[default])

返回键

key

对应的值,并从字典中移除该键值对;若不存在

key

,则返回

default

(默认为None)

d.popitem()

随机返回一个键值对并从字典里移除它

d.fromkeyset(iter,[initial])

将可迭代对象的元素设置为映射的键,使用

initial

参数作为这些键的值(默认为None)

d.get(key,[default])

返回键

key

对应的值,若键不存在,返回

default

(默认为None)

d.setdefault(key,[default])

若存在键

key

,则返回对应值;否则,令

d[key]=default

,然后返回

default

(默认为None)

d.update(m,[**kargs])

m

为映射或键值对迭代器,用以更新字典中对应条目*(批量更新)*

四、映射的弹性查询

进行映射查询时,我们希望能够处理找不到的键,得到一个默认值。一般有两种方式能够实现:

1.defaultdict

在实例化

collections.defaultdict

的时候,给构造方法提供一个可调用对象,当

__getitem__

遇到找不到的键的时候调用,作为目标键的值添加键值对。

如:新建字典

dd = collections.defaultdict(list)

,当键

new-key

dd

不存在的话,

dd['new-key']

会执行以下步骤:

调用

list()

创建空列表;

将新列表作为值,

new-key

作为键,添加到

dd

中;

返回新列表的引用

若在创 defaultdict 的时候没有指定可调用对象,则查询不存在的键会触发

KeyError

defaultdict 的可调用对象仅在

__getitem__

里被调用,在其他方法里完全不会起作用(如get)。

2.实现特殊方法__missing__

所有映射类型遇到找不到的键的时候,都会调用

__missing__

(

defaultdict

也是通过该方法实现)。可以通过这个方法自定义对象找不到某个键时会发生什么。

该方法只会被

__getitem__

调用,对

get

__contains__

方法的使用没有任何影响。

五、子类化UserDict

对于自定义映射类型来说,使用

UserDict

作为基类比

dict

要更加方便:内置类型的方法中会忽略子类覆盖的方法,再次调用原有的方法。

而 UserDict 并非 dict 的子类,但其

data

属性是一个 dict 实例,实际存储了 UserDict 中的数据。在实现 UserDict 方法时候,可以将具体的字典操作代理给

data

属性。

六、集合

对于添加与删除元素,集合的速度更快。Python中的集合有:

set

不可变类型

frozenset

一、散列型:由于集合底层的实现,

集合中的元素必须是可散列的

。而 set 本身是不可散列的,但 frozenset 是可散列的。

二、构造:

对于 set 有两种构造方法:字面量法

{...}

与构造函数法

set(iter)

。一般推荐使用字面量法,因其速度更快。

对于 frozenset 只能通过构造函数来创建。

三、

集合推导

:集合推导类似于列表推导,只不过将

[]

换为

{}

{i for i in range(32,256)}

集合操作

对于集合操作,若为中缀运算符,则要求两侧的被操作对象均为集合;但若为其他操作,则只要求传入的参数是可迭代对象

运算

运算符

|

求并集

&

求交集

-

求差集

e in s

判断元素

e

是否属于集合

s

<

/

<=

(

>

/

>=

)

判断集合是否包含/真包含

集合方法

方法

s.add(e)

将元素

e

添加到

s

s.clear()

删除

s

中所有元素

s.cop()

浅复制

s

s.discard(e)

s

中有

e

,则移除这个元素

s.pop()

s

中移除一个元素并返回

对于以上方法,若方法会原地修改集合,则不能用于 frozenset。

七、散列

散列表为字典与集合实现的底层机制,而基于这个机制

字典和集合的运算速度都很快

散列表

散列表为一个稀疏数组,表中的单元称表元。在字典的散列表中,每个键值对都占用一个表元,每个表元都有两个部分:对键的引用、对值的引用。而在集合的散列表中,存放的只有元素的引用(相当于只有键的字典)。Python 会设法保证至少 1/3 是空的,当达到这个阈值时,原有散列表会被复制到一个更大的空间中。

散列与相等:

散列表使用散列值来索引

。若两个对象比较时是相等的,则它们的散列值应该相等,否则散列表不能正常运行。

Python的散列查找算法:

而对于添加新元素与更新键值对,过程几乎与上面一样,只不过对于添加,在发现空表元的时候会放入新元素;对于更新,在找到相应表元后会替换新值。

散列表的使用导致了字典空间效率的低下:①散列表的稀疏性 ②表元中同时存储了键与值。

即,字典是一种用时间换取空间的数据结构.

键的次序取决于添加的顺序:往

dict

添加新键发生冲突时,会进行再散列,将新建存放到另一个位置,故键值对的次序取决于其添加进字典的顺序。

这就导致了相等的字典键值对顺序可能不一致

(添加键值对的过程中发生了冲突)。

往字典里添加新建可能改变已有键的顺序

,当添加一个键导致扩容时,新的散列表的顺序很有可能被打乱。如果在迭代字典的过程中,对字典进行修改,那么该循环很有可能通过一些键或重复迭代某些键。

利用反汇编函数

dis.dis

可以查看代码运行翻译成的字节码。

*其他字典:

collections.OrderedDict:有序字典,保持键添加的顺序不变;

collections.Counter:给键添加一个整数计数器,每次更新一个键的时候增加这个计数器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值