本文引用至: python基础类型之dict&set

在python中, 将数据结构分类了两种,一种是序列(sequence), 另外一种是字典(dictionary). 其中,序列也就是我们前面所说的 list and tuple. 字典就是这里将要说的两种-- dict and set
前面介绍了,list && set. 这里,我们就来探讨一下剩余两个datatypes

dict

dict 打个比方就相当于 js中的对象. 他实际就是一种散列表(hash)的形式. dict 中的内容是无序的, 但每一个值都是以key/value形式出现, 所以当我们需要查找值时, py会直接根据你调用的key来进行索引,最后返回你的值. 他的查找速度是极快的, 复杂度就是O(1)
而相应的损耗就是内存空间, 所以这也符合hash表的特征, 速度快, 空间大. 通过时间换空间的方式,进行索引.
ok, 现在我们来创建一个dict:

>>> my_dict = {1: 'apple', 2: 'ball'}
//key, 我们也是可以换的
>>> new_dict = {'name':'jimmy','age':18}
// 访问只能使用key
>>> new_dict['age']
18

实际上, dict就这么简单. 但是, 我们需要理解他和list的不同, 由于他的feature 是速度快, 空间大,便于查找. 所以这种方式也常用于, 数据存储和传输那一块.
那,有没有什么办法能 convert dict to list呢?
absolutely.
直接使用 list方法即可

>>> my_dict
{1: 'apple', 2: 'ball'}
>>> list(my_dict)
[1, 2]

不过这样的现实意义并不大, 因为,实际上,他只会截取你dict中的key 作为list的value.
但是, list是不能直接转换为dict的, 除非你是结合元组进行使用.

>>> my_dict = dict([(1,'apple'), (2,'ball')])
>>> my_dict
{1: 'apple', 2: 'ball'}

最后我们可以总结一下就是:
dict 转化

dict 中的相关方法

同样无外乎就是CRUD。 这里我们慢慢讲.

dict 添加

这里很容易理解, 即就是给dict添加新的内容. 不像, list中有关序列的append,extend,insert方法. 在dict中,只提供了setdefault(key[,value]),update([other]) 进行相关的添加操作.

  • setdefault(key[,value]): 用来向dict中指定添加相应的序列. 如果不存在,则新增. 如果存在 则该次添加默认无效, 并且返回已经存在的值. 实际上,这个方法,真的很有用. 当我们需要判断一个值是否存在,再添加时,就会用到该方法


>>> my_dict
{1: 'apple', 2: 'ball'}
>>> my_dict.setdefault(1,[2,3])
'apple'
//如果不存在则默认添加
>>> my_dict.setdefault(3,1)
1
  • update([other]): 该方法是用来批量加入dict。 other的类型可以为dict, 也可以为tuple+list. 我们看一下官方给的答案:

D.update([E, ]**F) -> None. Update D from dict/iterable E and F.

If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
In either case, this is followed by: for k in F:  D[k] = F[k]

上面那段话和keys方法扯上关系了. 实际上,keys是dict的方法. 所以就代表的着dict的类型. 如果你没有keys 方法, 这里就相当于使用for...in... 遍历数据结构,而能这样遍历的, 就只有tuple+list. 看个demo:

>>> my_dict.update({1:2,3:4})
// 直接添加dict, 没问题吧. 继续
>>> my_dict.update([(5,1)])

就酱. 另外,提醒一点,除了setdefault方法以外的其他方法,默认都会覆盖原有的key/value pair.

dict 删除

这里dict 提供了大概4种方法: pop,popitem,del, clear. 我们分开来说一下:

  • pop(k[,d]): 要知道,dict 不同于dict 是没有顺序的. 如果你的pop不带参数, 那就不能怪谁了, please go die. 所有pop的用法就是, 在dict中删除指定的k, 另外你也可以带上,d(就是value). 如果dict中的k不存在的话, 该方法就会返回d, 否则直接返回删除值.

//指定key删除
>>> my_dict.pop('age')
27
// 由于,ket->age已经被删除了, 这里我们使用补充的value作为备用,以防出错.
>>> my_dict.pop('age',12)
12 //直接返回实现设好的12
  • popitem(): 这个方法,就不用任何参数了, 他的作用就是,从你的dict中随便删除一个pair,并以tuple的形式返回. 但,如果dict已经是empty, 那么就 go die了.

>>> my_dict.popitem()
('name', 'Ranjit')
  • del : del 在这里 就和list是一样的了. 用来删除指定的值.

>>> del my_dict['age']
  • clear(): 不说了, 就是清空的意思

dict 获取

在list中,我们获取部分元素 直接使用分片就好了, 或者大不了使用copy呗. 但在dict中就没有这么方便了.
所以, 为了弥补这个defect, dict提供了几个比较好的方法.
有: fromkeys(seq[, v]),get(key[,d]),copy(),items(),keys(),values()
莫急,我们慢慢看

  • fromkeys(seq[, v]): 该方法,实际上就是提取公因式, 用来给不同的keys 使用同一个val. 生成一个新的dict. 所以,这也引出了下文会提到的comprehension.

>>> dic = dict.fromkeys([1,2,3],12)
  • get(key[,d]): 相比,直接通过dict[xx]访问方式而言, 我觉得这个方法,真的没有什么用. 比较好的也是他的一个判断, 当key不存在值,他不会报错,并且如果你设置好了d,那么不存在的话,就会返回d.

>>> my_dict.get('name')
'Ranjit'
// 不存在jimmy的key
>>> my_dict.get('jimmy','sexy')
'sexy'
  • copy(): 不说了, 就是全部复制

  • items(): 用来返回,dict_items的类型. 他的形式就相当于tupe+list

>>> my_dict.items()
dict_items([('name', 'Ranjit'), ('address', 'Downtown')])

只是他的类是dict_items

>>> type(my_dict.items())
<class 'dict_items'>
  • keys(): 以dict_keys的形式返回dict中的键值.

>>>my_dict.keys()
dict_keys(['name', 'address'])
  • values(): 同样, 以dict__values的形式,返回value值.

>>> my_dict.values()
dict_values(['Ranjit', 'Downtown'])

最后,说一下最后3种类型, dict_items,dict_keys,dict_values. 到底干嘛的.
官方解释是, 这些相当于只是一个快照(view). 并不会持续存在,这样做的目的就是为了节省内容. 而且,如果你想将两个 dict进行比较的时候, 实际上,只要比较他的dict.values,dict.keys 或者, dict.items 是否相同即可. 因为,这样比较快.(不过,由于无序,你也可以直接比较)

>>> dic.items() == my_dict.items()
True

另外,如果你想讲keys或者values保留下来,可以直接使用list方法进行转义即可.

>>> list(dic.values())
['jimmy', 'Downtown']

dict complement

最后再补充一下关于dict的 周边方法.

dict comprehension

这个和list类型,用来迅速生成一个dict

>>> squares = {x: x*x for x in range(6)}
>>> squares
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

只要后面是一个可以遍历的数据结构就行.
另外, 使用for...in... 遍历dict, 他的结果是遍历当中的key 而不是, value.

>>> for x in squares:
...     print(x)

JSON 操作

dict 在python中叫做字典, 而在js中 叫做对象. 将对象字符串化, 就是JSON的实质.
实际上, 这种格式,是非常利于网络传输的. 现在, 大部分web传输方式都是使用JSON (JavaScript Object Notation)格式, 而上面的书写方式, 只需要转为json即可。
py 提供了我们一个json的模块, 里面有一些基本方法,最常用的,要算dumps和loads.
做个类比:

  • dumps: 相当于js中的JSON.stringify()

  • loads: 相当于js中的JSON.parse()

来具体看看方法参数吧:

  • loads(s, encoding=None[,...]): 实践上,这是loads提供的参数配置, 一般而言, 我们只需要默认参数即可. 使用方法很简单:

>>> json_str
'{"shares": 100, "name": "ACME", "price": 542.23}'
>>> json.loads(json_str)
{'name': 'ACME', 'shares': 100, 'price': 542.23}

对比一下,引号应该就知道其中的意义了.

  • dumps(obj[,..]): 同样,dumps 我们使用默认参数即可. 用来将obj 转化为str.

>>> data
{'shares': 100, 'name': 'ACME', 'price': 542.23}
>>> json.dumps(data)
'{"shares": 100, "name": "ACME", "price": 542.23}'

同样,大家比较一下就知道了.
另外, 这里需要提及几点的是: 在和JSON相互转化的过程中, FalseTrue converted to false/true. None -> null. 另外json 中还提供了 load,dump方法,用来对文件进行操作. 有兴趣的同学,可以参考一下官方文档: json

来看张总结图谱吧
py dict相关方法

Set 剖析

这里,想要介绍一个, 专门为数学运算准备的数据结构--set. set不同于dict, 他没有成对的key/value。 他只会包含,不重复的value. 一个简单的set,我们可以这么写

>>> s = {1,2,3,4}
// 如果你要创建空的set的话, 请使用set()方法.
>>> s = set()
// 不然的话, 就是dict类型了

就是讲你所需要的值放在 curly braces里面即可.
我们来看看他最重要的feature--不重复

>>> s = {x for x in [1,1,1,1]}
>>> s
{1}

另外, set是不能包含mutable datatype. 比如 list。(tuple 可以)

>>> s = {[1,2,3]}
TypeError: unhashable type: 'list'
// 已经给出, 不能存放非 hash 值

实际上, set还有一个很重要的作用,就是用来 remove duplicates. 特别针对于list
使用方法就是直接使用set()进行过滤即可. 我们可以定义一个函数unique

def unique(l):
    l = set(l)
    l = list(l)
    return l

>>> unique([1,1,1])
[1]

那么,我们怎么访问set呢?
孩纸, 对不起,
同样, set和dict类型, 也存在CRUD操作, 不过,他还自带了innate buffer. 集合运算

set method

create 相关

py提供了两个方法, 一个是add, 一个是update.

  • add(ele): 该方法,用来添加一个ele. 但如果该ele存在, 那么该次添加就是useless

>>> new_set
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> new_set.add(10)
  • update(iterable): 该方法用来添加多个set元素. 参数必须是可以遍历的.比如,list,set,tuple,dict. 当然,如果是dict的话, 他只会添加key进去

>>> new_set.update({'a':1,'b':2})
{'a','b'}

delete 相关

在set中, 同样提供了几个可供处理的方法: discard,remove,pop,clear.
discard(ele)和remove(ele) 实际上是有点相像的. 唯一的difference是, 使用discard时, 如果元素不存在,不会报错,而remove会.

>>> my_set
{1, 3, 5}
>>> my_set.discard(2)
>>> my_set
{1, 3, 5}
>>> my_set.remove(2)
KeyError: 2

那set不是无序的吗? 为什么会有pop这个方法呢?
对比与dict 中的popitem方法而言, 在set中,pop就已经可以代表这个意思了. 即, 使用pop()方法,会随机删除 set中的某一个值.并且会返回删除的值. 如果为空的话,会报错

>>> new_set
{0, 1, 2}
>>> new_set.pop()
0

clear就是清空的意思,就酱.
对于list有tuple, 而set 对应的immutable datatype就是 frozenset. frozenset实际上就是 固定的set. 所以, 对于create 和 delete 方法而言是不能应用在frozenset上的. 那frozenset该怎么玩呢?

frozenset

定义一个frozenset, 可以直接使用frozenset() 方法.

  • frozenset(iterable): 它里面接受可以进行遍历的datatype, 上面所说的 set,list等都行

>>> A = frozenset([1, 2, 3, 4])
>>> A
frozenset({1, 2, 3, 4})

那我们什么时候会使用到呢?
表问我, 我也母鸡. 看心情吧

接下来,才应该是set的重头戏, 集合操作.

set 集合操作

简单的结合操作无外乎: 交(&),并(|),差(-),对称差(^). 简单的还有包含(⊆),真包含(⊂).
我们先来看几个容易理解的:

set Union

两个集合相并:
union

在python中, 我们可以使用| operator。 或者是union()方法

>>> A | B
{1, 2, 3}
>>> A.union(B)
//等价于
>>> B.union(A)

还记得, 并的对称性吧. A|B = B|A

set intersection

两个集合相交:
intersection

在python中, 我们就可以使用 & 表达式, 或者 intersection方法,来做.

>>> A & B
{4, 5}
>>> A.intersection(B)
{4, 5}
>>> B.intersection(A)
{4, 5}

set Difference

两个集合的差集:
difference
在python中, 我们就可以使用- 或者difference()方法来表示

>>> A - B
{1, 2, 3}
>>> A.difference(B)
{1, 2, 3}

这个就是上图的表达式

set Symmetric Difference

两个集合的对称差 [(A-B)∪(B-A)]:
symmetric
在python中,表达可以使用^ 或者symmetric_difference()方法.(你觉得那个简单?)

>>> A ^ B
{1, 2, 3, 6}
>>> A.symmetric_difference(B)

上面两个就是两个集合的基本操作. 并且衍生出另外一个set. 在python的set操作中, 还有判断两个集合是否相关的方法: isdisjoint(),issubset(),issuperset().
现在假设有集合A和集合B。

>>> B
{0, 1, 2, 3}
>>> A
{0, 1, 2}
  • isdisjoint(): 判断两集合是否相交. 记住, 包含并不是相交, 相交是指有一部分包括,有一部分不包括, 相当于就是两个圆外边界相交

>>> A.isdisjoint(B)  //两个的关系是包含的意思
False
>>> A.issubset(B)
True
  • A.issubset(B): 判断集合B是否包含集合A. 当然, 完全相等也算包含. 实际上就是数学中的⊆.

  • A.issuperset(B): 判断集合A是否包含集合B。 这里我就不绕了, 大家看情况使用即可.

>>> A.issubset(B)
True
>>> A.issuperset(B)
False

另外, 我们检查一个元素是否在另外一个set中,可以直接使用 in关键字了.
看个demo.

>>> A
{0, 1, 2, 3}
>>> 1 in A
True

到这里, set的基本内容,应该差不多了. 剩下的就是在实践中,不断磨练了.
看个总结图:

set 方法


villainhr
7.8k 声望2.2k 粉丝

下一篇 »
赋值trick

引用和评论

0 条评论