Python基础 - 3.容器类型

前言

在Python中,容器类型用于存储、组织和管理数据。主要的容器类型包括列表、元组、字典、集合等。它们各自有不同的特点和用途。

列表(List):
列表是有序的数据集合,它可以包含任何类型的数据元素,包括数字、字符串、甚至其他容器。
列表是可变的,这意味着可以在程序运行期间更改、添加或删除列表中的元素。
列表非常适合存储允许重复且需要经常修改的数据集合。

元组(Tuple):
元组也是有序的数据集合,但它是不可变的。一旦创建则无法更改其内容。
元组通常用于存放不应更改的数据,比如说函数的参数。
由于元组的不可变性,它可以用作字典的键,而列表不可以。

字典(Dictionary):
字典是一种存储键值对(key-value pairs)的数据结构,其中的键必须是唯一的。
字典是无序的集合,在Python 3.6及以上版本中,字典会维持插入顺序,方便遍历。
字典非常适合于需要快速查找、添加和删除的场景中。

集合(Set):
集合是不重复元素的无序集合。
集合支持数学的集合运算,如并集、交集、差集等。
集合常用于去重,因为它自动过滤掉了重复的元素。

 

3.1 字符串介绍

定义:双引号或者单引号中的数据,就是字符串。例如:

b = "www.baidu.com"
# 或者
b = 'www.baidu.com'

下标:就是标记空间的一个数字,有些文档叫它索引,个人觉得叫下标更能体现它的特点。

如果有字符串:name = 'abcdef',在内存中的实际存储如下:

(1)下标为正数时:

第0个空间 第1个空间 第2个空间 第3个空间 第4个空间 第5个空间
a b c d e f

(2)下标为负数时:

第-6个空间 第-5个空间 第-4个空间 第-3个空间 第-2个空间 第-1个空间
a b c d e f

特点:

每个字符单独存储,各占一个存储空间;为了方便标记处哪个空间存放的是哪个字符,Python使用了下标;
如果从左侧开始编号,那么下标从 0 开始;如果从右侧开始编号,那么下标从-1开始;
如果字符串只有三个字符:"abc",那么能用的下标为0、1、2不能使用超过2以上的,这种情况就是越界。越界很危险会导致程序崩溃。

 

下标的使用:

name = 'abcdef'

print(name[0])
print(name[1])
print(name[2])


# 运行结果
a
b
c

 

3.2 字符串切片

定义:

较为官方的说法:切片是指对操作的对象截取其中一部分的操作。通俗来说:一种能够从数据中取到一部分数据的方式。

例如:有一个字符串"abcdef",我们可以通过切片取到"cde"。切片不仅可以在字符串中应用,还可以对列表、元组等进行操作,简言之切片功能很重要。

使用方式:

#语法如下:
[起始:结束:步长]


#例1:
name = 'abcdef'
print(name[0:3])  #注意取不到下标为3的空间(左闭右开)

#结果:
abc

#例2:
name = 'abcdef'
print(name[2:])  # 取下标为2开始到最后的字符

#结果:
cdef

#例3:
name = 'abcdef'
print(name[1:-1])  # 取下标为1开始到右侧最后一个字符之前的所有字符

#结果:
bcde

#例4:
name = 'abcdef'
print(name[1:5:2])  # 步长为2表示间隔1个值取一次

#结果:
bd

#例5:
name = 'abcdef'
print(name[5:1:-1])  # 5: 起始位置,1: 结束位置 (不包含),-1: 步长,表示从右往左取值

#结果:
fedc


#例6:
name = 'abcdef'
print(name[::1])  # 起始位置: 未设置,结束位置: 未设置,1: 步长,表示从最左边取值到最右边(包含最右边)

# 结果:
abcdef


#例7:
name = 'abcdef'
print(name[::-1])  # 开始位置、结束位置都未指定,步长为-1,此时从最右取到最左

#结果:
fedcba

 

3.3 字符串内置方法

(1)find方法

检测str是否包含在 my_str中,如果是返回开始的索引值,否则返回-1。

# 基本格式:
my_str.find(str, start=0, end=len(mystr))


# 例如:
my_str = "welcome to www.tulingxueyuan.com"
print(my_str.find("to"))

# 结果:
8

# 说明:上述运行中数值8表示"to"这个字符串在原字符串的开始下标值是8

(2)rfind方法

类似于find()函数,不过是从右边开始查找,返回的索引是从左边开始。

(3)count方法

返回str在start和end之间在 my_str里面出现的次数。

(4)replace方法

把my_str中的str1替换成str2,如果count指定,则替换不超过count次。

# 基本格式:
my_str.replace(str1, str2,  mystr.count(str1))


# 例如:
my_str = "welcome to www.tulingxueyuan.com"

print(my_str.replace('w', 'W', 1))

# 结果:
'Welcome to www.tulingxueyuan.com'

(5)split方法

以str为分隔符切片my_str,如果maxsplit有指定值,则仅分隔maxsplit个子字符串。

# 基本格式:
my_str.split(str=" ", maxsplit)


# 例如:
my_str = "welcome to www.tulingxueyuan.com"

print(my_str.split(" "))
# 结果:
['welcome', 'to', 'www.tulingxueyuan.com']

print(my_str.split(" ", 1))
# 结果: 
['welcome', 'to www.tulingxueyuan.com']

(6)startswith方法

检查字符串是否是以指定的字符串开头, 是则返回True,否则返回False。

# 基本格式:
my_str.startswith('这里写入你指定的字符串')

# 例如:

In [1]: my_str = "welcome to www.tulingxueyuan.com"
...
In [4]: my_str.startswith('welcome')
Out[4]: True

In [5]: my_str.startswith('Welcome')
Out[5]: False

(7)endswith方法

检查字符串是否以指定字符串结束,如果是返回True,否则返回 False。

(8)lower方法

转换 my_str 中所有大写字符为小写。

# 基本格式:
my_str.lower()

# 例如:
In [8]: my_str = "WELCOME to www.tulingxueyuan.com"

In [9]: my_str.lower()
Out[9]: 'welcome to www.tulingxueyuan.com'

(9)upper方法

同理,转换 my_str 中所有小写字母为大写。

(10)strip方法

删除字符串两端的空白字符。

# 例如:
In [12]: my_str = "   welcome to www.tulingxueyuan.com   "

In [13]: my_str.strip()

Out[13]: 'welcome to www.tulingxueyuan.com'

(11)partition方法

把my_str以str分割成三部分,str前,str和str后。

# 基本格式:
my_str.partition(str)

# 例如:
In [14]: my_str = "welcome to www.tulingxueyuan.com"

In [15]: my_str.partition('to')
Out[15]: ('welcome ', 'to', ' www.tulingxueyuan.com')

(12)splitlines方法

按照行分隔,返回一个包含各行作为元素的列表。

# 基本格式:
my_str.splitlines()

# 例如:
In [16]: my_str = """welcome to www.tulingxueyuan.com
    ...: thank you
    ...: good good study day day up
    ...: """

In [17]: my_str.splitlines()
Out[17]: ['welcome to www.tulingxueyuan.com', 'thank you', 'good good study day day up']

(13)isalpha方法

如果my_str所有字符都是字母则返回True,否则返回False。

# 基本格式:
my_str.isalpha()

# 例如:
In [18]: my_str = "abc123"

In [19]: my_str.isalpha()
Out[19]: False

In [20]: my_str = "abc"

In [21]: my_str.isalpha()
Out[21]: True

(14)isdigit方法

如果my_str只包含数字则返回True,否则返回 False。

(15)isalnum方法

如果my_str所有字符都是字母或数字则返回True,否则返回False。

# 基本格式:
my_str.isalnum()

# 例如:
In [2]: my_str = 'abc123'

In [3]: my_str.isalnum()
Out[3]: True

In [4]: my_str = 'abc123_'

In [5]: my_str.isalnum()
Out[5]: False

(16)join方法

my_str中每个元素后面插入str,构造出一个新的字符串

# 基本格式:
my_str.join(str)

# 例如:
In [6]: my_str = '-'

In [7]: str_list = ['welcome', 'to', 'changsha']

In [8]: my_str.join(str_list)
Out[8]: 'welcome-to-changsha'

说明:
关于字符串的常见操作上面列举了十六个,其实还有很多;

不要死背,理解即可,忘记没关系,可以查阅资料;学会怎么用,什么时候用什么才是关键点。

 

3.4 列表介绍

引入

通过前面学习的字符串我们可以实现用它存储一串信息,例如存储一个人的名字顾安,那么如何存储咱们班所有同学的名字呢?

定义100个变量,每个变量存放一个学生的姓名可行吗?有更好的办法吗?

答:列表

定义

定义列表的方式是[ ],如下:

# 用列表存储了三名学生的姓名
stu_names = ['张三', '李四', '王五']

# 用列表存储了五位同学的考试分数
scores = [100, 99, 100, 95, 90]

基本使用

下标

列表中存储的多个数据,我们可以对这些数据任意的使用,方式是:通过下标可以实现定位,然后就可以用这个数据,例如:

stu_names = ['张三', '李四', '王五']
print(stu_names[0])  # 此时只输出张三
stu_names[0] = "顾安"
print(stu_names[0])  # 此时只输出顾安

注意:下标依然是从零开始

切片

切片具体的知识我们已经学习过了,在列表也是支持切片操作的。

stu_names = ['张三', '李四', '王五']
stu_names[1:3]  # 此时得到一个新列表 [李四', '王五']

列表逆序:

stu_names = ['张三', '李四', '王五']
stu_names = [::-1]  # 得到一个新列表['王五', '李四', '张三']

遍历

所谓列表遍历,就是指将列表中的所有的数据依次获取打印。

方式一:使用for循环 (首选)

stu_names = ['张三', '李四', '王五']
for name in stu_names:
    print(name)

# 结果:
张三
李四
王五

方式二:使用while循环

stu_names = ['张三', '李四', '王五']
length = len(stu_names)
i = 0
while i < length:
    print(stu_names[i])
    i += 1

# 结果:
张三
李四
王五

注意:
学习其他编程语言的同学,此时能够看到Python中的列表与C、C++、Java中的数组很类似:

相同点:列表和数组都能实现多个数据的存储

不同点:列表可以存储不同类似的数据,而数组只能存储相同数据类型。

 

3.5 列表的内置方法

列表,最大的特点能够存储多个数据,一般情况下我们需要对这个列表进行数据的增删改查,详细功能如下:

(1)数据增加(append、extend、insert)

append方法

通过append可以向列表添加元素。

# 格式:
列表.append(新元素数据)

# 例如:

# 定义列个表存储3个学生的姓名
stu_names = ['张三','李四','王五']
print("-----添加之前,列表的数据-----")
for name in stu_names:
    print(name)

# 提示、并添加元素
temp = input('请输入要添加的学生姓名:')
stu_names.append(temp)

print("-----添加之后,列表的数据-----")
for name in stu_names:
    print(name)

extend方法

通过extend可以将另一个列表中的元素逐一添加到列表中。

# 格式:
列表.extend(另外一个列表)

# 例如:
>>> a = [1, 2]
>>> b = [3, 4]
>>> a.append(b)
>>> a
[1, 2, [3, 4]]
>>> a.extend(b)
>>> a
[1, 2, [3, 4], 3, 4]

insert方法

insert(index, object)在指定位置index(索引,理解为下标即可)前插入元素object。

# 例如:
>>> a = [0, 1, 2]
>>> a.insert(1, 3)
>>> a
[0, 3, 1, 2]

(2)数据修改

修改元素的时候,要通过下标来确定要修改的是哪个元素,然后才能进行修改。

# 格式:
列表[下标] = 新数据

# 例如:

# 定义列个表存储3个学生的姓名
stu_names = ['张三', '李四', '王五']
print("-----修改之前,列表的数据-----")
for name in stu_names:
    print(name)

# 修改元素
stu_names[1] = '赵六'
print("-----修改之后,列表的数据-----")
for name in stu_names:
    print(name)

(3)数据查询(in、not in、count)

所谓的查找,就是看看指定的元素是否存在。查找的常用方法为:in(存在),如果存在那么结果为true,否则为false;not in(不存在),如果不存在那么结果为true,否则false。

in 与 not in 方法

# 例如:
# 待查找的列表
stu_names = ['张三','李四','王五']

# 获取用户要查找的名字
find_name = input('请输入要查找的姓名:')

# 查找是否存在
if find_name in stu_names:
    print('找到了名字')
else:
    print('没有找到')

count方法

查询元素个数。

# 格式:
列表.count("要查询的数据")  # 结果就是找到的数据的个数

# 例如:
In [5]: nums = [1, 2, 3, 4, 5, 1, 2, 3]

In [6]: nums.count(1)  # 查找的数据1 一共有2个,所以结果为2
Out[6]: 2

In [7]: nums.count(9)  # 没有找到数据9 所以结果为0
Out[7]: 0

(4)数据删除(del、pop、remove)

列表元素的常用删除方法有:

del:根据下标进行删除。

movie_names = ['加勒比海盗', '骇客帝国', '第一滴血', '指环王', '霍比特人', '速度与激情']

print('------删除之前------')
for name in movie_names:
    print(name)

del movie_names[2]  # 这里根据下标进行删除

print('------删除之后------')
for name in movie_names:
    print(name)

pop:删除最后一个元素。

movie_names = ['加勒比海盗', '骇客帝国', '第一滴血', '指环王', '霍比特人', '速度与激情']

print('------删除之前------')
for name in movie_names:
    print(name)

movie_names.pop()  # 删除最后1个

print('------删除之后------')
for name in movie_names:
    print(name)

remove:根据元素的值进行删除。

movie_names = ['加勒比海盗', '骇客帝国', '第一滴血', '指环王', '霍比特人', '速度与激情']

print('------删除之前------')
for name in movie_names:
    print(name)

movie_names.remove('指环王')  # 删除指定的数据

print('------删除之后------')
for name in movie_names:
    print(name)

(5)数据排序(sort、reverse)

sort方法是将列表按特定顺序重新排列,默认为由小到大,参数reverse=True可改为倒序,由大到小。reverse方法也是倒序。

>>> a = [1, 4, 2, 3]
>>> a.sort()
>>> a
[1, 2, 3, 4]
>>> a.sort(reverse=True)
>>> a
[4, 3, 2, 1]
>>> a = [1, 4, 2, 3]
>>> a
[1, 4, 2, 3]
>>> a.reverse()
>>> a
[3, 2, 4, 1]

 

3.6 列表嵌套

什么是列表嵌套?
类似while循环的嵌套,列表也是支持嵌套的,一个列表中的元素是一个列表类型那么这就是列表的嵌套。

school_names = [
    ['北京大学', '清华大学'],
    ['南开大学', '天津大学', '天津师范大学'],
    ['山东大学', '中国海洋大学']
]

应用

一个学校,有三个办公室,现在有八位老师等待工位的分配,请编写程序,完成随机的分配:

import random

# 定义一个列表用来保存3个办公室
offices = [[], [], []]

# 定义一个列表用来存储8位老师的名字
names = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']

# 遍历所有的老师,随机安排到0、1、2号办公室
for name in names:
    random_num = random.randint(0, 2)
    offices[random_num].append(name)

i = 1
for office_names in offices:
    print('办公室%d的人数为:%d' % (i, len(office_names)))
    i += 1
    for name in office_names:
        print("%s" % name, end=' ')
    print("\n")
    print("-" * 20)

运行结果如下: 因为是随机,所以每次运行结果不一定相同。

办公室1的人数为:1
G 

--------------------
办公室2的人数为:2
A B 

--------------------
办公室3的人数为:5
C D E F H

 

3.7 元组介绍

什么是元组?

元组是存储多个数据的一种方式。元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号(),列表使用方括号[]。

>>> aTuple = ('et',77,99.9)
>>> aTuple
('et',77,99.9)

元组的使用

访问元组

# 定义一个元组
nums = (100, 200, 300)

# 获取元组中的元素
print(nums[0])

# 遍历
for temp in nums:
    print(temp)

注意:不能修改元组,示例代码

# 定义一个元组
nums = (100, 200, 300)

nums[0] = 400  # 这里会报错,元组中的数据不能被修改

 

注意:

不能修改元组中的元素指的是如果当前元组中的元素为不可变对象则不能修改;

如果是可变对象在不修改元素类型的情况下可以修改可变对象中的值。

可变对象:list、dict、set

不可变对象:tuple、string、int、float、bool

 

3.8 集合介绍

什么是集合?
集合是一种能够存储多个数据的方式

它最大的特点是:数据不能重复

也就是说

列表可以存储多个数据,支持增删改查
元组可以存储多个数据,不能修改
集合依然可以存储多个数据,数据不能重复
可见Python发明的列表、元组、集合各有特点各有千秋,希望大家多练习以便更快掌握它们的精髓

集合的使用

定义

{元素1, 元素2, 元素3...}

示例

# 定义一个集合
nums = {100, 200, 300}

# 测试数据类型真的是集合吗?
print(type(nums))

# 遍历
for temp in nums:
    print(temp)

# 运行结果:
<class 'set'>
200
100
300

集合的数据去重

# 定义一个集合
nums = {100, 200, 200, 300, 300, 300}

# 测试数据类型真的是集合吗?
print(type(nums))

# 遍历
for temp in nums:
    print(temp)

集合无序

代码示例:

# 定义一个集合
set_data = {'a', 'b', 'c', 'd', 'e', 'f'}
print(set_data)

# 结果:
In [1]: set_data = {'a', 'b', 'c', 'd', 'e', 'f'}

In [2]: print(set_data)
{'c', 'd', 'f', 'b', 'a', 'e'}

注意:

列表、元组在定义时的顺序是怎样的,那么顺序就是怎样的;
而集合的实际存储顺序与定义的顺序没有什么关系,而是与一个特殊的算法有关(把数据进行了哈希,这个我们暂不做深入讨论,只需要知道集合的顺序不确定即可)。

 
内置方法

方法

描述

add()

为集合添加元素

clear()

移除集合中的所有元素

copy()

拷贝一个集合

difference()

返回多个集合的差集

difference_update()

移除集合中的元素,该元素在指定的集合也存在。

discard()

删除集合中指定的元素

intersection()

返回集合的交集

intersection_update()

返回集合的交集。

isdisjoint()

判断两个集合是否包含相同的元素,如果没有返回True,否则返回False

issubset()

判断指定集合是否为该方法参数集合的子集。

issuperset()

判断该方法的参数集合是否为指定集合的子集

pop()

随机移除元素

remove()

移除指定元素

symmetric_difference()

返回两个集合中不重复的元素集合。

symmetric_difference_update()

移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。

union()

返回两个集合的并集

update()

给集合添加元素

集合交并差运算代码示例

# 两个集合的交集运算
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

intersection = set1 & set2
print("交集:", intersection)  # 输出: {4, 5}

# 两个集合的并集运算
union = set1 | set2
print("并集:", union)  # 输出: {1, 2, 3, 4, 5, 6, 7, 8}

# 两个集合的差集运算
difference = set1 - set2
print("差集:", difference)  # 输出: {1, 2, 3}

# 对称差集运算(两个集合的差集的并集)
symmetric_difference = set1 ^ set2
print("对称差集:", symmetric_difference)  # 输出: {1, 2, 3, 6, 7, 8}

集合打印顺序问题 - 课后补充

在Python中,集合set是无序的数据结构,这意味着集合中的元素没有特定的顺序。当你打印一个集合时,可能会注意到它们似乎按照一定的顺序进行了排序,但实际上这只是打印的结果。

在Python中,集合的打印顺序是由实现的内部机制决定的。从Python 3.3开始,集合的打印顺序通常是根据元素的哈希值来确定的。由于哈希值是根据元素的值计算得出的,因此具有相同哈希值的元素在打印时通常会彼此靠近。这可能会给你一种集合是有序的错觉。

然而,需要注意的是,集合的打印顺序在不同的Python解释器、不同的操作系统或不同的运行环境下可能会有所不同。此外,集合的顺序在不同的操作中也可能发生改变,因为集合是可变的数据结构。

因此,重要的是要记住,集合本身是无序的,不能依赖于它们的打印顺序进行编程逻辑。如果你需要有序的集合,可以考虑使用有序集合SortedSet或使用列表list等其他数据结构来代替。

 

3.9 容器类型互转

引入

所谓互转,就是把一种数据类型在数值不变的情况下转换为另外一种数据类型。当前容器类型的互转不包含字典!!!

基本使用

nums1 = [11, 22, 33]  # 定义列表
nums2 = (44, 55, 66)  # 定义元组
nums3 = {77, 88, 99}  # 定义集合

# 列表转换为元组、集合
print("-----------")
nums1_tuple = tuple(nums1)
print(type(nums1_tuple))
nums1_set = set(nums1)
print(type(nums1_set))

# 元组转换为列表、集合
print("-----------")
nums2_list = list(nums2)
print(type(nums2_list))
nums2_set = set(nums2)
print(type(nums2_set))

# 集合转换为列表、元组
print("-----------")
nums3_list = list(nums3)
print(type(nums3_list))
nums3_tuple = tuple(nums3)
print(type(nums3_tuple))

快速去重
使用set,可以快速的完成对list、tuple中的元素去重复的功能

nums1 = [11, 22, 44, 33, 22, 11, 55, 666, 44, 33, 22]  # 列表类型
nums2 = (11, 22, 44, 33, 22, 11, 55, 666, 44, 33, 22)  # 元组类型

print(set(nums1))  # 将nums1转换为集合的时候,就自动去重了
print(set(nums2))  # 将nums2转换为集合的时候,就自动去重了

# 结果:
{33, 11, 44, 22, 55, 666}
{33, 11, 44, 22, 55, 666}

 

3.10 字典介绍

引入

场景一:声明一个列表保存学生信息

name_list = ['张三', '李四', '王五']

如果发现 "李四" 这个名字写错了,通过下标修改

name_list[1] = '赵六'

场景二:学生信息列表,每个学生信息包括学号、姓名、年龄等,如何从中找到某个学生的信息?

students = [[1001, "张三", 24], [1002, "李四", 23], [1005, "王五",24], ...]
假如上述列表有100个人的信息,此时会发现想要找到某个人的信息虽然我们可以数索引:0 1 2...但这也太麻烦了。
问:有没有更方便的方式呢?
通过上面的2个场景的描述,发现虽然列表可以很轻松的实现数据的增删改查,但当多个数据时,想要快速定位到某个数据就会很不方便。
基于此原因,Python发明了一种特殊的下标,可以快速的找到想要的数据。
拥有这种特殊下标的数据类型就是字典。

基本使用

# 格式:
{key: value, key2: value ...}

说明:

key可以理解为:我们自己可以定义的下标
value可以理解为:我们要存储的真正的数据
字典只要存储一个数据,就必须用key: value(我们常称为键值对)组成

代码示例
定义一个字典,存储顾安老师的信息

teacher_info = {'name': '顾安', 'age': 18, 'home': '湖南省长沙市'}

如果感觉一行太长,写不开,可以用如下的方式:

teacher_info = {
    'name': '顾安', 
    'age': 18, 
    'home': '湖南省长沙市'
}

说明:

字典能够存储多个数据
列表中找某个元素时,是根据下标进行的,字典中找某个元素时,是根据key(就是冒号:前面的那个值,例如上面代码中的name、home、age)
字典的每个元素由2部分组成,键:值

根据key访问value

teacher_info = {
    "name": "顾安",
    "age": 18,
    "home": "湖南省长沙市"
}

print(teacher_info['name'])  # 获取姓名
print(teacher_info['age'])  # 获取年龄
print(teacher_info['home'])  # 获取住址

# 运行结果:
顾安
18
湖南省长沙市

 

遍历字典(keys、values、items)
keys()方法
遍历字典的键(key)

teacher_info = {
    "name": "顾安",
    "age": 18,
    "home": "湖南省长沙市"
}

for key in teacher_info.keys():
    print(key)

# 结果:
name
age
home

values()方法
遍历字典的值(value)

teacher_info = {
    "name": "顾安",
    "age": 18,
    "home": "湖南省长沙市"
}

for val in teacher_info.values():
    print(val)

# 结果:
顾安
18
湖南省长沙市

items()方法
遍历字典的项(元素)

teacher_info = {
    "name": "顾安",
    "age": 18,
    "home": "湖南省长沙市"
}

for item in teacher_info.items():
    print(item)

# 结果:
('name', '顾安')
('age', 18)
('home', '湖南省长沙市')

 

3.11 字典的常见操作

(1)数据查询 - 普通方式

teacher_info = {
    "name": "顾安",
    "age": 18,
    "home": "湖南省长沙市"
}

print(teacher_info['QQ'])  # 当前字典不存在QQ这个键

# 结果:
Traceback (most recent call last):
  File "/Users/poppies/Desktop/字典.py", line 8, in <module>
    print(teacher_info["QQ"])
KeyError: 'QQ'

(2)数据查询 - get方式
在我们不确定字典中是否存在某个键而又想获取其值时,可以使用get方法,还可以设置默认值:

teacher_info = {
    "name": "顾安",
    "age": 18,
    "home": "湖南省长沙市"
}

print(teacher_info.get('QQ', '当前字典不存在QQ这个key'))  # 当前字典不存在QQ这个键

# 结果:
当前字典不存在QQ这个key

(3)数据修改
字典的每个元素中的数据是可以修改的,只要通过key找到,即可修改:

info = {'name': '班长', 'id': 100, 'sex': '男', 'address': '中国北京'}

new_id = input('请输入新的学号:')
info['id'] = int(new_id)

print('修改之后的id为: %d' % info['id'])

# 结果:
请输入新的学号:1010
修改之后的id为: 1010

(4)数据增加
新的key以及value就表示添加一个新的键值对

即:如果在使用变量名['键'] = 数据时,这个键在字典中不存在,那么就会新增这个元素。

info = {'name': '班长', 'id': 100, 'sex': '男', 'address': '中国北京'}

print(info)
info['web_address'] = "www.tulingxueyuan.com"  # 添加一个新的键值对
print(info)

# 结果:
{'name': '班长', 'id': 100, 'sex': '男', 'address': '中国北京'}
{'name': '班长', 'id': 100, 'sex': '男', 'address': '中国北京', 'web_address': 'www.tulingxueyuan.com'}

(5)数据删除
对字典进行删除操作,有一下几种:

del
clear()

del删除指定的元素
示例代码:

teacher_info = {'name': '顾安', 'age': 18, 'home': '湖南省长沙市'}

print(teacher_info)
del teacher_info['home']
print(teacher_info)

# 结果:
{'name': '顾安', 'age': 18, 'nome': '湖南省长沙市'}
{'name': '顾安', 'age': 18}

del删除整个字典
示例代码:

teacher_info = {'name': '顾安', 'age': 18, 'home': '湖南省长沙市'}

print(teacher_info)
del teacher_info
print(teacher_info)

# 结果:
{'name': '顾安', 'age': 18, 'nome': '湖南省长沙市'}
Traceback (most recent call last):
  File "/Users/poppies/Desktop/字典常见操作.py", line 7, in <module>
    print(teacher_info)
NameError: name 'teacher_info' is not defined

clear()清空整个字典元素
示例代码:

teacher_info = {'name': '顾安', 'age': 18, 'home': '湖南省长沙市'}

print(teacher_info)
teacher_info.clear()
print(teacher_info)

# 结果:
{'name': '顾安', 'age': 18, 'nome': '湖南省长沙市'}
{}

 

3.12 推导式

引入

推导式:就是一种能够快速生成数据的方式。例如,想要快速生成由1~20内所有偶数数组成的列表,就可以用推导式,代码如下:

[x for x in range(1, 21) if x % 2 == 0]

# 结果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

分类

根据最终要生成的数据,简单划分为:
列表推导式
集合推导式
字典推导式
注意:没有元组推导式,使用元组推导获取的结果是生成器对象(在Python进阶课程中学习)

(1)列表推导式
列表推导式:一种可以快速生成列表的方式

代码格式:

[变量 for 变量 in 可迭代对象]

案例一:

In [1]: a = [x for x in range(4)]

In [2]: a
Out[2]: [0, 1, 2, 3]

In [3]: a = [x for x in range(3, 4)]

In [4]: a
Out[4]: [3]

In [5]: a = [x for x in range(3, 19)]

In [6]: a
Out[6]: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

In [7]: a = [x for x in range(3, 19, 2)]

In [8]: a
Out[8]: [3, 5, 7, 9, 11, 13, 15, 17]

案例二:列表推导式中用到了if

注意:列表推导式如果for中用到了if,for不用写:

In [9]: a = [x for x in range(3, 10) if x % 2 == 0]

In [10]: a
Out[10]: [4, 6, 8]

In [11]: a = [x for x in range(3, 10) if x % 2 != 0]

In [12]: a
Out[12]: [3, 5, 7, 9]

案例三:在列表推导式中使用两个for循环

In [13]: a = [(x, y) for x in range(1, 3) for y in range(3)]

In [14]: a
Out[14]: [(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

案例四:在列表推导式中使用三个for循环

In [15]: a = [(x, y, z) for x in range(1, 3) for y in range(3) for z in range(4, 6)]

In [16]: a
Out[16]: 
[(1, 0, 4),
 (1, 0, 5),
 (1, 1, 4),
 (1, 1, 5),
 (1, 2, 4),
 (1, 2, 5),
 (2, 0, 4),
 (2, 0, 5),
 (2, 1, 4),
 (2, 1, 5),
 (2, 2, 4),
 (2, 2, 5)]

练习

请写出一段Python代码实现分组:一个list里面的元素,比如[1,2,3,...100]变成[[1,2,3],[4,5,6]....]

参考答案:

a = [x for x in range(1,101)]
b = [a[x: x + 3] for x in range(0, len(a), 3)]
print(b)

(2)集合推导式

集合推导式:一种快速生成集合的方式

示例代码:

In [5]: a = {x for x in range(1, 21) if x % 2 == 0}

In [6]: type(a)
Out[6]: set

In [7]: a
Out[7]: {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}

集合推导式中也可以用if等,与列表推导式在格式上很类似,这里就不做过多的介绍,请类别列表推导式进行学习

 

(3)字典推导式

字典推导式:一种快速生成字典的方式

案例一:快速生成一个1~10内key为某个数此时value为平方的字典

{x: x ** 2 for x in range(1, 11)}

# 结果:
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}

案例二:快速生成一个1~10内key可以1时value为2,key为2时value3....依次类推的字典

{x: (x + 1) for x in range(1,11)}

# 结果:
{1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10, 10: 11}

练习

编写代码用推导式,实现如下效果(列表中嵌套字典)

[{1: 1},
 {2: 4},
 {3: 9},
 {4: 16},
 {5: 25},
 {6: 36},
 {7: 49},
 {8: 64},
 {9: 81},
 {10: 100}]

参考代码:

[{x: x ** 2} for x in range(1, 11)]

 

3.13 拆包

引入

拆包:是一种快速提取数据的方式。例如,有一个元组(11, 22, 33, 44)想快速的提取每个元素且赋值给num1, num2, num3, num4这4个变量,普通的做法,较为繁琐:

nums = (11, 22, 33, 44)  # 定义一个元组
num1 = nums[0]  # 通过下标来提取
num2 = nums[1]  # 通过下标来提取
num3 = nums[2]  # 通过下标来提取
num4 = nums[3]  # 通过下标来提取

拆包的方式,可以见非常简洁:

num1, num2, num3, num4 = (11, 22, 33, 44)  # 一行代码搞定

列表拆包
示例:

a, b = [11, 22]
print(a)
print(b)

# 结果:
a, b = [11, 22]
print(a)
print(b)

元组拆包
示例:

a, b = (11, 22)
print(a)
print(b)

# 结果:
11
22

集合拆包
示例:

a, b = {11, 22}
print(a)
print(b)

# 结果:
11
22

字典拆包
一般用法

a, b = {"name": "顾安", "age": 18}
print(a)
print(b)

# 结果:
name
age

默认取到的是字典的key,而不是value

常见用法

teacher_info = {"name": "顾安", "age": 18}

for k, v in teacher_info.items():
    print('k = %s, v = %s' % (k, v))

# 结果:
k = name, v = 顾安
k = age, v = 18

注意点
在没有使用不定长参数的情况下=右边要拆的数据元素的个数要与=左边存的变量个数相同。

错误示例如下:

a, b = [11, 22, 33]

# 结果:
ValueError                                Traceback (most recent call last)
<ipython-input-19-887c339c8076> in <module>
----> 1 a, b = [11, 22, 33]

ValueError: too many values to unpack (expected 2)

使用不定长参数的情况下(了解即可):

In [1]: int_list = [1, 2, 3, 4, 5]

In [2]: a, *b, c = int_list

In [3]: print(a, b, c)
1 [2, 3, 4] 5

In [4]:

经典面试题:交换两个变量的值
方式一:普通方式

a = 4
b = 5
print("交换之前a=%d, b=%d" % (a, b))

# 额外定义一个变量,用来临时使用
c = a
a = b
b = c
print("交换之后a=%d, b=%d" % (a, b))

# 结果:
交换之前a=4, b=5
交换之后a=5, b=4

方式二:巧妙方式

a = 4
b = 5
print("交换之前a=%d, b=%d" % (a, b))

# 巧妙之处(没有用额外的变量)
a = a+b
b = a-b
a = a-b
print("交换之后a=%d, b=%d" % (a, b))

# 结果:
交换之前a=4, b=5
交换之后a=5, b=4

方式三:拆包方式

a = 4
b = 5
print("交换之前a=%d, b=%d" % (a, b))

a, b = b, a
print("交换之后a=%d, b=%d" % (a, b))

# 结果:
交换之前a=4, b=5
交换之后a=5, b=4

说明:

a, b = b, a首先要计算=右边b, a此时他们会被当做一个元组即(b, a)就相当于(5, 4)
然后再将a, b = (5, 4)进行计算,此时a为5,b为4

 

3.14 深浅拷贝

● 深拷贝和浅拷贝需要注意的地方就是可变元素的拷贝:
○在浅拷贝时,拷贝出来的新对象的地址和原对象是不一样的,但是新对象里面的可变元素(如列表)的地址和原对象里的可变元素的地址是相同的,也就是说浅拷贝它拷贝的是浅层次的数据结构(不可变元素),对象里的可变元素作为深层次的数据结构并没有被拷贝到新地址里面去,而是和原对象里的可变元素指向同一个地址,所以在新对象或原对象里对这个可变元素做修改时,两个对象是同时改变的,但是深拷贝不会这样,这个是浅拷贝相对于深拷贝最根本的区别。

●也可以这样理解:
○深拷贝就是完全跟以前就没有任何关系了,原来的对象怎么改都不会影响当前对象
○浅拷贝时,原对象的list元素改变的话会改变当前对象,如果当前对象中list元素改变了,也同样会影响原对象。
○浅拷贝就是藕断丝连
○深拷贝就是离婚了

 
深拷贝
●克隆一份,修改拷贝后的对象中的可变元素不对原对象内容产生影响
●copy模块中的deepcopy()

import copy

list1 = [["张三", "李四"], "王五", "赵六", "钱七"]
list2 = copy.deepcopy(list1)   # 进行深拷贝

# 打印 list1 和 list2 两个列表的内存地址 => 结果不一样
print(id(list1))    # 3132367069640
print(id(list2))    # 3132368415752

# 打印 list1 和 list2 两个列表中的子列表的内存地址 => 结果不一样
print(id(list1[0]))     # 3132368414728
print(id(list2[0]))     # 3132368415688


list2[0][0] = "安娜"

# 结果 list2 列表修改了,但是不影响list1列表数据
print(list2)    # [['安娜', '李四'], '王五', '赵六', '钱七']
print(list1)    # [['张三', '李四'], '王五', '赵六', '钱七']

浅拷贝
修改拷贝后的内容中的可变数据,原对象内容随之修改
列表函数copy()进行浅拷贝

list1 = [["张三", "李四"], "王五", "赵六", "钱七"]
list2 = list1.copy()   # 进行浅拷贝

# 打印 list1 和 list2 两个列表的内存地址 => 结果不一样
print(id(list1))    # 2105959073864
print(id(list2))    # 2105989035464

print('-' * 30)

# 打印 list1 和 list2 两个列表中的子列表的内存地址 => 结果一样
print(id(list1[0]))     # 2105989035592
print(id(list2[0]))     # 2105989035592


list2[0][0] = "安娜"

# 结果list2列表修改了,list1列表数据也修改了
print(list2)    # [['安娜', '李四'], '王五', '赵六', '钱七']
print(list1)    # [['安娜', '李四'], '王五', '赵六', '钱七']

copy模块中的copy()方法

import copy

list1 = [["张三", "李四"], "王五", "赵六", "钱七"]
list2 = copy.copy(list1)   # 进行浅拷贝

# 打印 list1 和 list2 两个列表的内存地址 => 结果不一样
print(id(list1))    # 2105959073864
print(id(list2))    # 2105989035464

print('-' * 30)

# 打印 list1 和 list2 两个列表中的子列表的内存地址 => 结果一样
print(id(list1[0]))
print(id(list2[0]))

list2[0][0] = "安娜"

# 结果list2列表修改了,list1列表数据也修改了
print(list2)    # [['安娜', '李四'], '王五', '赵六', '钱七']
print(list1)    # [['安娜', '李四'], '王五', '赵六', '钱七']

曹达华的附属金卡

# 现有女警司有额度为200000元的信用卡,卡号为:20200520,已使用的额度:15000
# 现需要实现曹达华也需要绑定这张信用卡进行付款

card = ["女警司", 20200520, [200000, 15000]]    # 女警司名下的信用卡

c_card = card.copy()    # 曹达华账户也开了一张绑定女警司信用卡的信用卡,且修改姓名和卡号
c_card[0] = "曹达华"
c_card[1] = 20200521
print(c_card)   # 打印出曹达华的信用卡信息 ['曹达华', 20200521, [200000, 15000]]

card[2][1] += 2000   # 此时女警司使用了信用卡且刷了2000元

print(c_card)  # 此时曹达华的信用卡额度也随之变化

# 运行结果如下
# ['曹达华', 20200521, [200000, 15000]]
# ['曹达华', 20200521, [200000, 17000]]    # 女警司刷卡后,曹达华所持的信用卡已使用的额度随之增长
© 注意事项
THE END
点赞1
评论 共2条

请登录后发表评论