python序列之字典

字典也是序列(Sequence)。看到字典,我们能想到查字典,一本字典里的字那么多,我们通过笔画,拼音等作为依照,很快能查到一个字。python的字典也差不多,特点是查找数据特别快。

弄清楚字典之前,先要弄清楚键值对,也就是key:value的形式,比如'name':'Tom'。

其中,键(key)必须是不可变的对象,比如数字:1;2;1.1等,字符串:'name';'我爱你'等,元组:(1,);(1,2,3)等。原因是字典底层用键计算hash时,要求键不可改变,要不然就找不到数据了。

值(value)可以是任意类型的数据。

另外,字典是无序的,也就是字典没有索引,只能通过键来查找数据或者访问键所对应的数据。

目录

一,字典的创建方式:

1,使用大括号{}把键值对包起来创建

2,使用dict函数

3,使用zip()函数

4,通过dict对象的fromkeys方法

二,字典元素的访问:

1,通过键来访问

2,通过字典对象的get方法访问元素

3,列出字典所有的键值对

4,列出字典对象所有的键。

5,列出字典对象所有的值。

6,获取字典的长度和元素在不在字典里

三,字典元素的增添,修改,删除:

1,增添

2,修改

3,删除

四,字典解包及序列解包:

五,字典底层核心原理:


一,字典的创建方式:

1,使用大括号{}把键值对包起来创建

int_a = 3
float_b = 1.1
bool_tr = True
str_str = '我爱你'


def func():
    print(666)


tu = (1,)
li = []
dict1 = {int_a: 12, float_b: 1, bool_tr: 2, str_str: 6, func: 12, tu: 12, "我爱你": "我爱你"}
dict2 = {li: 12}
#     dict2 = {li: 12}
# TypeError: unhashable type: 'list'
# 创建dict2的时候用列表li作为键报错

由上面的代码可见函数对象也能作为键。另外,字典dict,集合set,列表list是可变对象,不能作为键。

键不能重复,值可以重复。就像查字典,读音只有一种类型,比如‘拼’的读音pin只有一个,可以通过pin来查到拼,但是查到‘拼’这个字还可以通过提手旁来查到。也就是键不能重复,值可以重复。

空字典的创建:{}里啥也不写

dict2 = {}

2,使用dict函数

2.1 用dict函数创建空字典:

d = dict()
print(d)
# {}

2.2 给dict函数传一个可迭代对象,但是这个可迭代对象要拿出两个数据,也就是必须以键值对的形式拿出来数据。例如:[(1, 2), ('name', 'tom'), ('age', 18)],[]是列表,是可迭代对象,里面是三个元组,每个元组有两个元素,恰好是键值对的形式。

也可以把[]换成(),即((1, 2), ('name', 'tom'), ('age', 18)),因为元组也是可迭代的。

d = dict([(1, 2), ('name', 'tom'), ('age', 18)])
print(d)
# {1: 2, 'name': 'tom', 'age': 18}

2.3 给dict函数传入一连串的关键字参数,关键字参数也是键值对的形式

d = dict(a=1, b=2, c=3, d='dict', bool_copy=True)
print(d)
# {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}}

关键字参数名字遵从标识符的命名规范。

3,使用zip()函数

zip()函数又名拉链函数。

zip函数需要两个参数,这两参数都是可迭代对象,调用后返回一个zip可迭代对象(相当于生成键值对的一个算法)。

key = [1, 2, 3]
value = (1, 2, 3)
key_and_value = zip(key, value)
print(key_and_value)
d = dict(key_and_value)
print(d)
# <zip object at 0x00000274291FF848>
# {1: 1, 2: 2, 3: 3}

4,通过dict对象的fromkeys方法

参数为一个可迭代对象,对象里面的元素皆为不可变类型。创建只有键但是没有确定值的字典,值都变为None了。

key = [1, 2, 3]
d = dict.fromkeys(key)
print(d)
# {1: None, 2: None, 3: None}

简记为:剑来

二,字典元素的访问:

1,通过键来访问

语法格式为在[]里面写键。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
print(d['a'], d['bool_copy'])
# 1 True

2,通过字典对象的get方法访问元素

需要给get方法一个键作为参数,键存在的话返回键对应的值,否则返回None或者自定义的值。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
print(d.get('d'))
print(d.get('666'), '木有')
print(d['mmd'])  # 没有mmd这个键就会报KeyError异常
#     print(d['mmd'])
# KeyError: 'mmd'
# dict
# None 木有

3,列出字典所有的键值对

使用dict对象的items()方法。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
print(d.items())
print(type(d.items()))
# dict_items([('a', 1), ('b', 2), ('c', 3), ('d', 'dict'), ('bool_copy', True)])
# <class 'dict_items'>

4,列出字典对象所有的键。

使用dict对象的keys()方法。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
print(d.keys())
# dict_keys(['a', 'b', 'c', 'd', 'bool_copy'])

5,列出字典对象所有的值。

使用dict对象的values()方法。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
print(d.values())
# dict_values([1, 2, 3, 'dict', True])

6,获取字典的长度和元素在不在字典里

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
print(len(d))
print('a' in d)
# 5
# True

只能判断键在不在字典里,值不行。

三,字典元素的增添,修改,删除:

1,增添

1,利用键来添加

如果之前不存在新加的键,则直接加上去;如果想要加的键已经存在了,则覆盖之前的。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
d['mmd'] = 'mmd'
d['a'] = 100
print(d)
# {'a': 100, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True, 'mmd': 'mmd'}

2,使用字典dict对象的update方法,需要给update方法传入一个字典作为参数,也就是update(字典对象)。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
d1 = {'q': 'q', 'a': 100}
d.update(d1)
print(d)
# {'a': 100, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True, 'q': 'q'}

同样的,如果之前不存在新加的键,则直接加上去;如果想要加的键已经存在了,则覆盖之前的。

2,修改

1,使用键来修改

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
d['a'] = 100
print(d)
# {'a': 100, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}

2,使用update方法来覆盖

3,删除

1,del语句

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
del d['a']
del(d['b'])
print(d)
# {'c': 3, 'd': 'dict', 'bool_copy': True}

2,使用dict对象的pop方法,把键作为参数。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
d.pop('a')
print(d)
# {'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}

3,使用dict对象的clear方法,清空字典。

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
print(d)
# {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
d.clear()
print(d)
# {}

4,使用dict对象的popitem方法,随机删除一个键值对(因为字典是无序的,所以随机)

d = {'a': 1, 'b': 2, 'c': 3, 'd': 'dict', 'bool_copy': True}
d.popitem()
print(d)
# {'a': 1, 'b': 2, 'c': 3, 'd': 'dict'}
d.popitem()
print(d)
# {'a': 1, 'b': 2, 'c': 3}
d.popitem()
print(d)
# {'a': 1, 'b': 2}

四,字典解包及序列解包:

将多个值赋给一个变量时,Python会自动将多个值封装成元组,这个功能就称为序列封包。

反过来,序列解包可以为多个变量赋值。要求接收值得变量个数与解包序列里面的数据个数相同,会逐个给变量赋值。

列表list,元组tuple,字典dict,enumerate枚举对象,filter对象,range对象都可以解包。

x, y, z = (1, 2, 3)
a, b, c = 1, 2, 3
(d, e, f) = 1, 2, 3
[m,n,p] = [1,2,3]

def func():
    return 1, 2, 3


g, h, i = func()
print(x, y, z)
print(a, b, c)
print(d, e, f)
print(g, h, i)
# 1 2 3
# 1 2 3
# 1 2 3
# 1 2 3

字典解包时是利用字典的键进行处理。

d = {'name': 'tom', 'age': 18}
a, b = d
print(a, b)
# name age

如果要利用字典的值进行处理的话,则需要用dict对象的values方法。dict.values()返回一个dict_values对象,这个对象与列表类似。

d = {1: 1, 2: 2}
print(d.values())
# dict_values([1, 2])

如果要对键值对进行处理的话,则需要用dict对象的items方法。dict.items()方法返回一个元素为二元组的序列,也就是dict_items对象。

d = {1: 1, 2: 2}
print(d.items())
# dict_items([(1, 1), (2, 2)]),列表里面有两个元组,每个元组有两个数据,称为二元组

另外也可以用运算符‘*’来解包元组,也就是把元组()给解开不要括号。函数调用时的不定长位置参数就是这样的。

def func(*args):
    print(args)
    print(*args)
# (1, 2, 3, 4)
# 1 2 3 4

func(1, 2, 3, 4)
# 这里把1,2,3,4都传给了args,属于把多个数据赋值给一个变量,实际就是封包。
# args就是一个元组,用*来解包。

另外也可以用运算符‘**’来解包字典,从而去掉{}。但是解包后仍然是一个键值对,仍需要用{}包起来。

print(*[1, 2, 3], 4, *(5, 6))
print(*range(4), 4)
print({*range(4), 4, *(5, 6, 7)})
print({'x': 1, **{'y': 2}})  # 看这里**解包字典
# 1 2 3 4 5 6
# 0 1 2 3 4
# {0, 1, 2, 3, 4, 5, 6, 7}
# {'x': 1, 'y': 2}
dict1 = {1: 2, 2: 3}
print({**dict1})
# {1: 2, 2: 3}

def func(**kwargs):
    print(kwargs)
    print(type(kwargs))
    print(kwargs.items())
# {'a': 1, 'b': 2, 'c': 3}
# <class 'dict'>
# dict_items([('a', 1), ('b', 2), ('c', 3)])

func(a=1, b=2, c=3)

当接受的变量个数与要解包序列里面的数据个数不一样时,需要像下面这样操作。

a, b, *c = range(10)
print(a, b, c, type(c))
m, n, k, *d, e, f = range(10)  # *d会自动确定数量,相当于可变位置参数的意思
print(m, n, k, d, e, f)
# 0 1 [2, 3, 4, 5, 6, 7, 8, 9] <class 'list'>
# 0 1 2 [3, 4, 5, 6, 7] 8 9

类似于函数形参,*var通吃多个位置实参。不同之处在于,var类型是list而不是元组。这里的var代表变量名。

五,字典底层核心原理:

字典对象的核心是散列表。散列表是一个稀疏数组,也就是一个数组里边存在没有数据的位置,即给他分配了内存块空间,但是这个内存块空间里没有数据。这个空间也称为bucket,bucket内存块分为两部分,一个是键对象的引用,一个是值的引用。换句话说,一个键值对在内存中占的空间就叫做bucket。

字典储存数据时,先用内置函数(builtin functions)的hash()函数计算键的散列值,再用bin()函数将计算得出的散列值转为二进制。利用字典底层数组长度(长度一般为2^n次个)来确定偏移的位置(利用的是n),确定偏移位置后,把数据存在那里,但实际上是存的数据对象的id地址)。

访问字典元素时,也是通过散列值去找数据。如果键不存在的话,也就是访问到了空的内存块,则会报KeyError异常。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值