Python基础-12 容器——字典

十二、容器——字典

1. 字典概述

- 定义

dictionary(字典) 是 除列表以外 Python 之中 最灵活 的数据类型

和列表的区别

  • 列表有序 序列
  • 字典是“键值对”的 无序可变序列(3.5之后是有序的)

- 字典定义格式

d = {key1: value1, key2:value2, ...}

d = {}
d = dict()

b = {'name':'gaoqi','age':18,'job':'programmer'}
b = dict(name='gaoqi',age=18,job='programmer')
b = dict([("name","gaoqi"),("age",18)])

通过 zip()创建字典对象

k = ['name','age','job']
v = ['gaoqi',18,'techer']
d = dict(zip(k,v))
d  # {'name': 'gaoqi', 'age': 18, 'job': 

- 特点

  • key 是索引
  • value 是数据
  • 可以取任何数据类型,但 只能使用不可变类型,即 字符串数字元组
  • key一般情况下用字符串类型数据充当
    • 即可hash 的对象都可以作为key
    • 理论上所有不可变的类型都可以作为key
  • 每一个键值对是一个元素
  • 键必须是唯一的
xiaoming = {"name": "小明",
            "age": 18,
            "gender": True,
            "height": 1.75}

用法总结:

  1. 键必须可散列 (hash)

    1. 数字、字符串、元组,都是可散列的。
    2. 自定义对象需要支持下面三点:
      1. 支持 hash()函数
      2. 支持通过__eq__()方法检测相等性。
      3. a == b 为真,则 hash(a) == hash(b)也为真。
  2. 字典在内存中开销巨大,典型的空间换时间

  3. 键查询速度很快

  4. 往字典里面添加新建可能导致扩容,导致散列表中键的次序变化。因此,不要在遍历字 典的同时进行字典的修改。

- 应用场景

  • 尽管可以使用 for in 遍历 字典
  • 但是在开发中,更多的应用场景是:
    • 使用 多个键值对,存储 描述一个 物体 的相关信息 —— 描述更复杂的数据信息
    • 多个字典 放在 一个列表 中,再进行遍历,在循环体内部针对每一个字典进行 相同的处理
card_list = [{"name": "张三",
              "qq": "12345",
              "phone": "110"},
             {"name": "李四",
              "qq": "54321",
              "phone": "10086"}
             ]

2. 元素访问

使用字典获取字典中的数据

格式:

  • 字典变量名[key]
    • 区别:访问时,如果用了不存在的key,会报错
  • 字典变量名.get(key)【推荐】
    • 区别:访问时,如果用了不存在的key,会返回None

注意

  • 字典也是通过下标(key)方式来访问元素,但是字典没有索引(下标编号)

3. 遍历

- 键、键值显示方法

  • items():列出所有的键值对
  • keys():列出所有的键
  • values():列出所有的值

- 四种遍历方式

方式1

for k in d:
    print(k,':',d[k])

方式2

# keys()方法
for k in d.keys(): # 这里的`d.keys`是列表
    print(k,':',d[k])
  • 这里的d.keys是列表

方式3

# values()方法
for v in d.values(): # 这里的`d.values`是列表
    print(v)
  • 这里的d.values是列表
  • 这里只能获取到值,无法获取key

方式4

# items()方法1
for item in d.items():# 这里的`d.items`是有元组元素的列表
    print(item)
# items()方法2
for k,v in d.items(): # 这里是解包过程
    print(k, ':', v)

4. 字典增删改查

  • 利用字典变量名[key]来赋值,如果key在字典中不存在,就是向字典增加数据
d['a'] = 1
d['b'] = 2
  • update():新字典中所有键值对全部添加到旧字典对象上。
    • 如果 key 有重复,则直 接覆盖。
a = {'name':'gaoqi','age':18,'job':'programmer'}
b = {'name':'gaoxixi','money':1000,'sex':'男的'}
a.update(b)
a  # {'name': 'gaoxixi', 'age': 18, 'job': 'programmer', 'money': 1000, 'sex': '男的'}

关键字 / 函数 / 方法说明
popitem()删除末位的一个键值对
pop(key)指定key来删除任意键值对
并返回对应的“值对象”
clear()清空字典
del d[key]删除指定key的键值对【关键字
del d删除字典【关键字
del(d[key])删除指定key的键值对【函数
del(d)删除字典【函数

如果赋值时的key在字典中存在,则通过key来修改该值

d[key] = 新的值

注意

  • 字典中的key具有唯一性
  • 如果key不存在,就是向字典中添加值
  • key是不可以修改的

如果想要修改key,只能先删除key,在重新添加键值对

同字典的引用,访问

  • 字典变量名[key]

    • 区别:访问时,如果用了不存在的key,会报错
  • 字典变量名.get(key)

    • 区别:访问时,如果用了不存在的key,会返回空值
  • len() 键值对的个数

  • 'key' in d:检测一个“键”是否在字典中

*字典练习(名片管理)

函数一: 建立名片-> 建立好的名片
函数二: 显示名片-> 接收谁打印谁

# 定义字典函数

def creat_card():
    # 使用字典来保存每张名片的数据
    # name,age,address
    card = {}
    card['name'] = input('请输入姓名')
    card['age'] = input('请输入年龄')
    card['address'] = input('请输入地址')

    return card


# 显示字典内容函数

def show_card(card):
    for k, v in card.items():
        print(f'{k},{v}')


card=creat_card()
show_card(card)

5. 无序字典和有序字典(了解)

  • 在 python3.5之前, dict 类型是无序的 ,key无序
    • 写入顺序和显示顺序不同
  • 在 pyhton3.5之后,都是有序
    • 写入顺序和显示顺序相同

6. 字典核心底层原理(了解)

- 核心底层原理

字典对象的核心是散列表。散列表是一个稀疏数组(总是有空白元素的数组),数组的 每个单元叫做 bucket。每个 bucket 有两部分:一个是键对象的引用,一个是值对象的引 用。

  • bucket,或者叫表元

由于,所有 bucket 结构和大小一致,我们可以通过偏移量来读取指定 bucket。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GiWbte4t-1610202477509)(Media/image-20201230202700268.png)]

- 将一个键值对放进字典的底层过程

a = {}
a["name"]="gaoqi"

假设字典 a 对象创建完后,数组长度为 8:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-548g5wam-1610202477511)(Media/image-20201230202821664.png)]

我们要把”name”=”gaoqi”这个键值对放到字典对象 a 中,首先第一步需要计算 键”name”的散列值。Python 中可以通过 hash()来计算。

bin(hash("name"))  # '-0b1010111101001110110101100100101' 

由于数组长度为 8,我们可以拿计算出的散列值的最右边 3 位数字作为偏移量,即 “101”,十进制是数字 5。我们查看偏移量 5,对应的 bucket 是否为空。如果为空,则 将键值对放进去。如果不为空,则依次取右边 3 位作为偏移量,即“100”,十进制是数字4。再查看偏移量为 4 的 bucket 是否为空。直到找到为空的 bucket 将键值对放进去。流 程图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tSCuWJZd-1610202477513)(Media/image-20201230203031821.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pqTOHpOx-1610202477516)(Media/image-20201230203040063.png)]

- 扩容

python 会根据散列表的拥挤程度扩容。“扩容”指的是:创造更大的数组,将原有内容 拷贝到新数组中。 接近 2/3 时,数组就会扩容。

- 根据键查找“键值对”的底层过程

我们明白了,一个键值对是如何存储到数组中的,根据键对象取到值对象,理解起来就 简单了。

a.get("name")  # 'gaoqi'

当我们调用 a.get(“name”),就是根据键“name”查找到“键值对”,从而找到值 对象“gaoqi”。

第一步,我们仍然要计算“name”对象的散列值:

> bin(hash("name"))  # '-0b1010111101001110110101100100101' 

和存储的底层流程算法一致,也是依次取散列值的不同位置的数字。 假设数组长度为 8,我们可以拿计算出的散列值的最右边 3 位数字作为偏移量,即“101”,十进制是数字 5。我们查看偏移量 5,对应的 bucket 是否为空。如果为空,则返回 None。如果不为空, 则将这个 bucket 的键对象计算对应散列值,和我们的散列值进行比较,如果相等。则将对 应“值对象”返回。如果不相等,则再依次取其他几位数字,重新计算偏移量。依次取完后, 仍然没有找到。则返回 None。流程图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ADmLRLv5-1610202477518)(Media/image-20201230203301791.png)]

**打印表格练习

姓名年龄薪资城市
高小一1830000北京
高小二1920000上海
高小五2010000深圳
r1 = {"name":"高小一","age":18,"salary":30000,"city":"北京"}
r2 = {"name":"高小二","age":19,"salary":20000,"city":"上海"}
r3 = {"name":"高小五","age":20,"salary":10000,"city":"深圳"}
tb = [r1,r2,r3]

#获得第二行的人的薪资
print(tb[1].get("salary"))

#打印表中所有的的薪资
for i in range(len(tb)): # i -->0,1,2
print(tb[i].get("salary"))

#打印表的所有数据
for i in range(len(tb)):
print(tb[i].get("name"),tb[i].get("age"),tb[i].get("salary"),tb[i].get("city"))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值