❤ 摘要
本章主要讲解python的数据类型。
数据类型分为不可变数据类型和可变数据类型。
知识点
- 不可变数据类型:
- 数字
- 字符串
- 元祖
- 可变数据类型:
- 列表
- 集合
- 字典
▶️ 基本数据类型
在 Python 中,数据类型分为不可变数据类型和可变数据类型。
-
不可变数据类型:当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称不可变数据类型。数字、字符串、元组属于不可变数据类型。
-
可变数据类型:当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称可变数据类型。列表、集合、字典属于可变数据类型。
我们可以通过内置函数 type()
查看对象的类型。通过内置函数 id()
查看对象的内存地址。
1. 数字
在 Python 中存在三种不同的数字类型: 整数、浮点数、复数,数字类型用于存储数值,属于不可变数据类型。
我们进入 Python 交互模式来验证一下:
a = 5
type(a)
id(a)
a = 6
id(a)
运行效果如下:
可以看到,变量 a 是整数类型,当 a 的值发生了变化,内存地址就会改变。
1.1 整数类型
整数类型(int
)通常被称为是整型或整数,包括正整数和负整数,不带小数点。Python 3 中,整型具有无限的精度,就是说没有大小限制。Python3 中没有 Python 2 中的 long 类型,而是将 long 类型和 int 类型整合到了 int 类型。
1.2 整数-布尔型
布尔类型(bool)也叫布尔、布尔型,是整型的子类型。布尔类型是两个常量对象 False
和 True
,它们用来表示逻辑上的真假。内置函数 bool() 可被用来将任意值转换为布尔值。
在数字运算时,布尔类型相当于整数 0(False
)和 1(True
)。
我们可以做个实验,用 bool 类型和数字进行简单的运算。
True + 5
False * 3
运行效果如下:
1.3 浮点型 float
浮点数类型通常也叫浮点型,是使用 C 语言的 double 类型来实现,可以近似表示数学中的实数。
浮点型由整数部分与小数部分组成,也可以使用科学计数法表示(1.5e2 = 1.5 x 10² = 150.0)
需要注意的是,像 1.1
和 2.2
这样的数字因为在二进制浮点中没有精确的表示,导致浮点数运算时有时候会出现意想不到的结果,比如下面的演示:
运行效果如下:
这就像一个陷阱一样,虽然很多编程语言也会有同样的情况。
❤️ 求近似值 round()
这时候你可能会想到求近似值,Python 内置函数 round()
可以获得近似值。其语法为 round(number, ndigits)
,可选参数 ndigits 是指小数点后几位精度,为空时会返回最接近的整数。
我们看两个例子:
a = 1.1 + 2.2
round(a)
round(a, 2)
运行效果如下:
虽然也能获得正确结果,但你也不能确定到底小数点后几位精度才会获得正确结果。而且 round()
函数通常情况下能实现四舍五入,但有时候也会产生让你抓狂的结果。
运行效果如下:
这个情况也是因为十进制小数不能正确被浮点数表示。
你可能想问,浮点数到底有没有办法获得正确的结果?
❤️ 正确的浮点数运算 decimal
这时候,就该 decimal
模块闪亮登场了。decimal
模块就可以实现快速正确的十进制浮点数计算,让我们得到正确的计算结果。
下面看一个例子:
from decimal import Decimal
a = Decimal('1.1') + Decimal('2.2')
float(a)
可以看到,我们得到了正确的结果。这里需要注意的是 Deciaml()
必须是字符串形式的数字。
运行效果如下:
1.4 复数类型
复数由实数部分和虚数部分构成,可以用 a + bj
,或者 complex(a,b)
表示,复数的实部 a 和虚部 b 都是浮点型
。要从一个复数 z 中提取这两个部分,可使用 z.real
和 z.imag
。
依次运行下面语句,感受一下:
a = 5 +6j
type(a)
a.real
a.imag
b = complex(2,3)
b
b.real
b.imag
运行效果如下:
1.5 数字类型转化
我们可以使用构造函数 int()、 float() 和 complex() 分别构造特定类型的数字。
int() 函数
int()
函数在将数字类型转换为整数时,参数为空返回 0 ;十进制整数返回本身;浮点数采用向下取整;二进制整数和十六进制整数都会返回对应的十进制整数。
int() #参数为空
int(1) #十进制整数
int(1.3) #浮点数
int(1.9) #浮点数
int(0b101) #二进制整数
int(0x32) #十六进制整数
运行效果如下:
int()
函数在将字符串作为参数时,该字符串中的数字只能是整数。其他进制整数在转换时需要指定可选参数 base
,默认是 10(十进制),另外可以选择 0 或者 2-36,指定 0 会根据书写方式自动判断。
int('10') #字符串内是十进制整数
int('0b101',base=0) #字符串内是二进制整数
int('0x32',base=0) #字符串内是十六进制整数
int('0b101',base=2) #字符串内是二进制整数
int('0x32',base=16) #字符串内是十六进制整数
运行效果如下:
需要注意的是,int()
函数在将字符串作为参数时,字符串内不能是浮点数形式。
a = '1.5'
int(a)
运行效果如下:
那如果有一个字符串类型的数字 '1.3'
该如何转换成整数类型呢?
float() 函数
float()
可以将数字或者字符串转换到一个浮点数类型。
float(1)
float(1.5)
float('1')
float('1.5')
运行效果如下:
前面我们提到,int()
函数不能将字符串类型的浮点数作为参数,那我们如何将字符串 '3.1415926'
转换为整数类型呢?
首先使用 float()
函数将字符串类型转换为浮点数类型,然后使用 int()
函数将浮点数转换为整数类型。
a = float('3.1415926')
b = int(a)
print(b)
运行效果如下:
将 int()
函数和 float()
函数结合一下:
int(float('3.1415926'))
运行效果如下:
complex() 函数
complex(x) 将 x 转换到一个复数,实数部分为 x,虚数部分为 0。
complex(5)
运行效果如下:
complex(x, y) 将 x 和 y 转换到一个复数,实数部分为 x,虚数部分为 y。
complex(5,3)
运行效果如下:
1.6 数字运算
Python 解释器其实完全可以作为一个计算器来使用,前面章节我们也进行过好几次简单的计算。接下来我们将演示 Python 中常用的数字运算。
print(3 + 5) #加法
print(9 - 3) #减法
print(3 * 5) #乘法
print(10 / 3) #除法
print(10 // 3) #整除,向下取整
print(10 % 3) #取余,除法运算之后返回余数
print(2 ** 10) #乘方,2 的 10 次方
运行效果如下:
Python 完全支持混合运算:当一个二元算术运算符的操作数有不同数值类型时,"较窄"类型的操作数会拓宽到另一个操作数的类型
,其中整数比浮点数窄,浮点数比复数窄。不同类型的数字之间的比较,同比较这些数字的精确值一样。
a = 5
b = 3.1
c = complex(3)
d = a + b
e = a + c
type(d)
type(e)
运行效果如下:
比如这里的a+b,整数比浮点数窄,最终是浮点型。
浮点型比复数窄,最终是复数
2. 字符串
在 Python 中处理文本数据时使用 str
对象,通常称为 字符串
。 字符串是 Python 中最常用的数据类型。
字符串是由 Unicode 编码构成的不可变数据类型。
上节提到,我们可以通过内置函数 type()
查看对象的类型。通过内置函数 id()
查看对象的内存地址。
接下来,我们在终端进入 Python 交互模式来验证一下:
字符串变化,地址变化,是 不可变数据类型
2.1 字符串索引
字符串的本质是字符的有序组合,在 Python 中,没有单字符类型,统一都是字符串类型。
字符串可以通过索引(下标访问)获取到对应位置的字符。你可以把索引理解成序号,不过和大部分编程语言一样,索引是从 0 开始的,在 字符串长度-1
的位置结束,如下图:
跟c语言的有些类似,从0开始到len-1结束,总共还是len长度。
我们进入 Python 交互模式继续实验。
a = "Hello"
a[0]
a[1]
a[2]
a[3]
a[4]
a[5] #此处因为超出范围,会报错。
逆方向索引
除了正方向的正索引,Python 还支持逆方向的负索引。
我们在 Python 交互环境来实验一下:
a = "Hello"
a[-5]
a[-4]
a[-3]
a[-2]
a[-1]
因为字符串是不可变数据类型,我们如果给某个索引位置赋值就会报错。
a = "12345"
a[0] = "a"
所以不能直接赋值。
2.2 字符串切片
切片的基本语法
除了索引,Python 还支持切片。索引用于获取单个字符,切片用于获取子字符串。
切片的基本语法是 string[start:end]
,start 默认是 0,end 默认到行尾。切片的操作“包头不包尾”,我们下面举例说明。
a = "Hello"
a[0:3] #返回索引 0,1,2 位置的字符
a[2:4] #返回索引 2,3 位置的字符
a[:4] #start参数默认是0,所以返回索引 0,1,2,3 位置的字符
a[3:] #end 默认到行尾,返回索引 3,4 位置的字符
a[-3:-1] #返回索引 -3,-2 位置的字符
a[-2:-1] #返回索引 -2 位置的字符
a[-2:] #end 默认到行尾,返回索引 -2,-1 位置的字符
a[::] #start 默认 0 ,end 默认到行尾,所以返回整个字符串
运行效果如下:
大致你按上面图片上的划分好。
切片的步长
切片中其实还有第三个参数 步长
,语法是 string[start:end:step]
。
步长可以是正数,也可以是负数,但不能为 0 。
当步长为负数时,start 的默认值是行尾,end 默认值是 0 。但 start 和 end 依旧满足“包头(start)不包尾(end)”,区别只是 start 比 end 的索引值数字大。
我们通过下面的例子,来理解一下步长的使用。
a = "123456789"
a[0:9:2] #将全部字符串以步长 2 选取。
a[2:7:3] #将索引 2 到索引 7 之间的字符,以步长 3 选取。
a[::-1] #步长 -1 可实现对字符串的翻转,此处表示对整个字符串翻转
a[5:1:-1] #步长 -1,将索引 5 到 索引 1 之间的字符翻转
运行效果如下:
越界问题
另外,切片会自动处理索引 end 的越界问题。
a = "123456"
a[2:10]
a[-3:-100:-1]
运行效果如下:
不用考虑越界问题。
2.3 转义字符
在很多编程语言、数据格式、通信协议中,通常会使用转义字符来表示一些特殊的字符。比如 URL 链接中会使用 %
进行转义,而 C 语言、Java、Python 都是使用反斜杠(\
)进行转义
续行符 \
print('hello \
world!')
运行效果如下:
引号 '
和 "
在 Python 中,单引号字符串中如果使用单引号可能会出现解释器无法识别的问题,所以我们就需要使用转义字符对字符串中的单引号进行转义。
print('It's OK!') #'s单引号无法识别
print('It\'s OK!') # 单引号' \转义
运行如下:
可以看到,不转义会报错,而转义之后不会报错。双引号也是一样的。
响铃 \a
print("\a")
因为实验环境不支持发声,大家可以在自己的电脑上尝试。
运行效果如下:
可以看到,运行之后标签上出现了响铃的图标。
退格(Backspace) \b
退格符会将光标退回前一个字符,不会删除光标后面的字符。但当退格符后边有新的字符时,将会覆盖退回的那个字符。
print('hello \bworld !') # 此处会退格后继续书写
print('hello world !\b') #此处退格符后面没有内容,所以没有变化。
换行 \n
换行(\n
)是光标到下一行。
print("Hello World!\nHello World!")
运行效果如下:
回车 \r
回车(\r
): 回到一旧行(当前行)的开头。(即光标目前所在的行为旧行)
print("123456\rs")
光标回到本行开头位置续写s
横向制表符 \t
print("Hello\tWorld!")
运行效果如下:
纵向制表符 \v
print("Hello\vWorld!")
运行效果如下:
八进制
表示字符串ASCII表需要转换为十进制:比如110十进制表示72,对应H
1~3位八进制数据所表示的 ASCII 字符。
print("\110\145\154\154\157\40\127\157\162\154\144\41")
运行效果如下:
十六进制
4位十六进制数据所表示的字符。
print("\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21")
运行效果如下:
避免转义 \
当我们遇到上述特殊字符但不需要转义时,我们可以在特殊字符前面加上反斜杠 \
避免转义。比如我们有一个路径 D:\tt\no\reseach
。
print("D:\tt\no\reseach") #默认输出的效果 \可能会被识别为转义符号
print("D:\\tt\\no\\reseach") #\避免转义之后
运行效果如下:
可以看到,默认输出的结果简直面目全非,而加上反斜杠 \
避免转义之后,输出了我们想要的结果。
2.4 字符串运算符
此处我们介绍一些字符串常用的运算符操作。
其中 in
和 not in
操作具有与比较>、< 操作相同的优先级。 +
(拼接) 和 *
(重复) 操作具有与对应数值运算相同的优先级。
in
操作符
如果字符串包含指定字符就返回 True,否则返回 False。
'e' in 'Hello'
'f' in 'Hello'
运行效果如下:
not in
操作符
如果字符串不包含指定字符就返回 True,否则返回 False。
'e' not in 'Hello'
'f' not in 'Hello'
运行效果如下:
字符串拼接(+
)
字符串可以使用 +
将两段字符串进行拼接。
'Hello' + ' World' # World 前面有个空格
'明天是' + '周六'
运行效果如下:
重复运算符(*
)
字符串和数字 n 相乘表示将字符串重复 n 次。
'=' * 15 + '测试' + '=' * 15
'Hello ' * 4
运行效果如下:
原始字符串(r
)
原始字符串
,是在引号前面加上 r
或 R
,这样遇到特殊字符就不会转义,而是普通输出。
print("C:\Windwos\no\reseach") #默认输出的效果
print(r"C:\Windwos\no\reseach") #原始字符串效果
运行效果如下:
2.5 字符串格式化
为了解决数字和字符串拼接错误
前面我们学习了使用 +
运算符实现对字符串的拼接,但是当如果我们想把数字和字符串拼接到一起时就会报错。
'今年是' + 2021 + '年'
运行效果如下:
当然,我们可以使用 str()
函数将数字转换为字符串格式。
'今年是' + str(2021) + '年'
运行效果如下:
这样虽然能解决问题,但是当我们有多个需要转换的字符,就让整个字符串变得很混乱。接下来我们就开始学习更好的解决方案,字符串格式化。
f-string 格式化
f-string 是 Python 在 Python 3.6 引入的格式化方案,是在普通字符串前面加上 f
或 F
,然后在字符串中使用大括号( {}
)引入变量或表达式,这种写法让字符串的书写变得简洁优雅。。
year = 2021
month = 4
day = 1
f"今天是{year}年{month}月{day}日"
运行效果如下:
格式说明符
在上面的基础用法之外,还可以使用可选的格式说明符,写在冒号(:
)后面。
浮点数说明符f
.2f
是指小数点后两位小数,f
是定点表示法,在没有指定精度时,会对浮点数采用小数点后 6 位有效数位的精度。
pi = 3.1415
f'圆周率保留两位小数是:{pi:.2f}' #指定精度
f'圆周率保留两位小数是:{pi:f}' #未指定精度
运行效果如下:
使用四舍五入取精度:
最小字符宽度(列对齐) :整数
如果冒号(:
)后面是一个整数,是为该字段设置最小字符宽度,常用于列对齐:
name1 = 'Bob'
age1 = 20
name2 = 'John'
age2 = 25
print(f'{name1:6}=>{age1:6}\n{name2:6}=>{age2:6}')
运行效果如下:
可以看到,因为限定了字符宽度为 6,不够的部分就会用空格进行填充,从而实现对齐效果。
如果是数字,还可以指定用 0 填充,就会在数字前面加 0。
total = 2000
print(f'金额总数:{total:08} 元')
运行效果如下:
千位分隔符
数字还可以使用 _
或者 ,
作为千位分隔符,让数字的阅读更加方便。
f'{100000000000}'
f'{100000000000:_}'
f'{100000000000:,}'
运行效果如下:
另外 _b
, _o
, _x
可以让二进制、八进制、十六进制每隔 4 个数码进行分隔。
f'{0b10000000:_b}' #二进制分隔表示
f'{128:_b}' #十进制数会先转二进制,然后分隔表示
f'{10000:_o}' #十进制数转八进制,然后分隔表示
f'{12800000:_x}' #十进制数会先转十六进制,然后分隔表示
运行效果如下:
百分比
可以使用 %
将数字转换为百分比形式。和 f
转换一样,不指定精度会按小数点后 6 位精度。
f'{0.25:%}' #不指定精度
f'{0.25:.2%}' #指定精度
运行效果如下:
其他修饰符 !a !s !r
还有一些修饰符可以在格式化前转换值。!a
对应 ascii()
函数,!s
对应 str()
函数,!r
对应 repr()
函数。
name = '苏轼'
print(f'{name!a}')
print(f'{name!s}')
print(f'{name!r}')
运行效果如下:
参考:
时间类型格式化
import datetime
d = datetime.datetime(2021, 10, 1, 8, 15, 58)
'{:%Y-%m-%d %H:%M:%S}'.format(d)
运行效果如下:
format 格式化
位置引用
format 格式化是将传递给 format
方法的对象传递到花括号内,使用如下:
print('We are the {} who say "{}!"'.format('knights', 'Ni'))
还可以在花括号中加上的数字表示传递给 str.format()
方法的对象所在的位置。
print('{0} and {1}'.format('spam', 'eggs'))
print('{1} and {0}'.format('spam', 'eggs'))
运行效果如下:
关键字引用
在位置引用之外,还可以使用关键字引用。
print('他今年 {age} 岁,在{city}工作。'.format(age=25, city='北京'))
运行效果如下:
格式化方式
对于字符或者数字的格式限定和上面的 f-string
基本类似,只是需要将需要引用的值放到 format()
方法内。需要注意的是 format()
方法不支持表达式。
pi = 3.1415926
'圆周率是:{:.2f}'.format(pi)
运行效果如下:
% 格式化
%
运算符也可用于字符串格式化,不过因为有很多怪异特性,导致很多错误,官方已经不推荐使用,我们这里只做简单介绍。
'%s %s'%('Hello','World')
'圆周率是:%.2f'%(3.1415926)
运行效果如下:
2.6 三引号 保留空白
使用三引号的字符串可以跨越多行,而且可以将所有的空白字符都包含在该字符串中。如果有保持样式的需求,那么就需要使用三引号。
print('''\
===========字符串===========
三引号字符串会保留空白字符,
从而实现保持样式的效果
''')
运行效果如下:
2.7 字符串方法
查看方法列表 dir函数
字符串对象有很多内建方法,我们通常会使用 dir()
函数查看。dir()
函数会列出该对象的属性和方法。
a = 'hello'
dir(a)
运行效果如下:
查看帮助 help函数
当我们想知道某个方法的使用方法,我们会使用 help
函数查看。比如,我们想知道 upper
方法是如何使用的。
a = 'hello'
help(a.upper)
运行效果如下:
帮助文档告诉我们,upper
方法会返回这个字符串的大写版本。帮助文档查看完毕,按 q
退出。
接下来,我们先测试刚刚查看的效果,然后再介绍几个常用的字符串方法,更多的方法的使用大家可以使用 help()
函数去查看。
upper()
方法返回大写的字符串
a = 'hello world!'
a.upper()
运行效果如下:
lower()
返回小写的字符串
a = 'Hello World!'
a.lower()
运行效果如下:
swapcase()
返回字符串大小写交换后的版本
a = 'Hello World!'
a.swapcase()
运行效果如下:
replace(old,new)
对字符串中的子字符串进行替换
a = 'Hello World!'
a.replace('World','Lanqiao')
运行效果如下:
strip()
方法默认会删除开头和结尾的空白字符:
a = ' Hello World ! '
a.strip()
运行效果如下:
也可以指定开头和结尾的其他字符
a = '==============Hello World!=============='
a.strip('=')
需要注意的是,strip()
方法只能删除开头和结尾
的字符。
split()
方法默认以空格作为分隔符对字符串进行拆分
split()
方法默认以空格作为分隔符对字符串进行拆分,连在一起的空格会被视为单个字符,分隔之后会以列表形式返回(我们会在后面章节介绍列表)。
a = 'Hello World Hello World'
a.split()
运行效果如下:
当然,也可以指定分隔符。
a = 'hello,world'
a.split(',')
运行效果如下:
join()
方法可以使用指定字符串连接多个字符串。
a = 'Hello Wolrd'
'-'.join(a.split())
运行效果如下:
以下实例展示了join()的使用方法:
- symbol = "-";
seq = ("a", "b", "c");# 字符串序列
print symbol.join( seq );
以上实例输出结果如下:
a-b-c
find()
方法可以返回要查找的子字符串的最小索引
前面我们在运算符部分介绍了 in
运算符,它可以判断一个字符串是不是另一个字符串的子字符串,但有时候我们还需要知道子字符串的位置。
a = 'Hello World'
a.find('Wo')
运行效果如下:
所以,字符 Wo
的索引从 6 开始。
当要查找的子字符不存在时将返回 -1。
a = 'Hello World'
a.find('Story')
运行效果如下:
len()
函数
我们可以通过 Python 的内置函数 len()
获得字符串的长度。
a = "Hello"
len(a)
运行效果如下:
3 元组
3.1 元祖的创建
使用一对圆括号来表示空元组: ()
a = ()
type(a)
运行效果如下:
使用一个后缀的逗号来表示单元组: a, 或 (a,)
a = (5) #当缺少逗号时
print(a)
type(a)
b = (5,) #加上逗号之后
print(b)
type(b)
运行效果如下:
单元组一定要加上逗号,否则不会被当成元组处理。
使用以逗号分隔的多个项: a, b, c or (a, b, c)
a = '中国','日本','朝鲜'
type(a)
b = ('中国','日本','朝鲜')
type(b)
使用内置的 tuple()
或 tuple(iterable)
terable 指可迭代对象,像字符串、元组、列表、字典、集合都是可迭代对象,但数字不是可迭代对象。
a = tuple() #生成一个空元组
print(a)
type(a)
number = '123456789'
tuple(number)
运行效果如下:
也就是把字符串number变为元祖类型。
3.2 元组的索引和切片
元组和字符串的一样,也可以使用下标索引来访问元组中的值:
t = ('a','b','c','d','e')
t[0] #访问元素
t[4] #访问元素
t[0:3] #切片
t[::-1] #翻转
运行效果如下:
3.3 元组的修改
因为元组是不可变数据类型,当我们试图通过索引去修改元组的某个元素时,将会报错。
a = ('a','b','c','d','e')
a[0] = 'f'
运行效果如下:
但我们有时候也会有修改数据的需求,这时候我们就可以结合 +
运算符和切片操作来实现。
a = ('a','b','c','d','e')
a = ('f',) + a[1:]
print(a)
运行效果如下:
需要注意的是,虽然我们实现了元组的修改,但此时的元组对象已经发生了变化,所以我们本质上是新建了一个元组。
3.4 元组的运算符
与字符串一样,元组也有很多可以使用的运算符,比如 +
、*
、in
等。
+
运算符
a = (1,2,3)
b = ('3','4',5)
c = a + b
print(c)
运行效果如下:
*
运算符
a = (1,3,5)
a * 3
运行效果如下:
in
和 not in
运算符
a = (1,3,5,7,9)
print(1 in a)
print('5' in a) #注意元素的类型
print(3 not in a)
运行效果如下:
3.5 元组解包
在我们创建元组时 a = 1,2,3
是 元组打包
的例子,所以我们使用逆操作实现 元组解包
。
a = 1,2,3
print(a)
x,y,z = a
print(x)
print(y)
print(z)
运行效果如下:
3.6 元组的常用函数和方法
count()
方法可以统计某个元素的的数量
a = (1,2,3,1,5,3,7,8,9)
a.count(1)
运行效果如下:
len()
函数可以统计元素的个数
a = (1,2,3,4,5,6,7,8,9)
len(a)
运行效果如下:
max()
函数可以返回元组中元素最大值。
a = (1,5,6,3,2)
max(a)
运行效果如下:
min()
函数可以返回元组中元素最小值。
a = (1,5,6,3,2)
min(a)
运行效果如下:
4 列表
4.1 列表定义和类型(可变)
列表(list
)是方括号([]
)内用逗号分隔的一组值,列表可以包含不同类型的元素,但一般情况下,会在其中存储类型相同的元素。
列表是可变数据类型,我们可以做个实验来验证这一点。
a = [1,2,3]
print(a)
print(type(a),id(a))
a.append(4) #新增元素
print(a)
print(type(a),id(a))
可以发现,通过列表的内置方法给列表新增了一个元素,但 id
值仍然保持不变。
4.2 列表的创建
使用一对方括号来表示空列表: []
a = []
print(a)
type(a)
运行效果如下:
使用方括号,其中的项以逗号分隔: [a] 或 [a, b, c]
a = [1]
print(a)
type(a)
b = ['q','w','e','r']
print(b)
type(b)
运行效果如下:
使用列表推导式: [x for x in iterable],iterable
是可迭代对象。
我们首先以元组作为可迭代对象。
t = (1,2,3,4,5,6,7)
a = [i for i in t]
print(a)
type(a)
运行效果如下:
再来用字符串作为可迭代对象。
n = 'abcdefg'
a = [i for i in n]
print(a)
type(a)
运行效果如下:
使用类型的构造器: list() 或 list(iterable)
a = list() #创建一个空列表,与 a = [] 一样
print(a)
type(a)
n = 'abcdefg'
b = list(n) #将字符串转换为列表
print(b)
type(b)
运行效果如下:
4.3 列表的索引和切片
和字符串、元组一样,列表也支持索引和切片。
s = [1, 2, 3, 4, 5, 6, 7, 8, 9]
s[0] #获取索引 0 处的元素
s[-1] #获取索引 -1 处的元素
s[2:5] #切片
s[::-1] #翻转列表
s[::2] #步长为 2 生成新列表
运行效果如下:
4.4 列表元素的添加
append()
方法可以在列表末尾追加元素
a = [1,2,3]
print(a)
a.append(4) #末尾追加元素 4
print(a)
运行效果如下:
extend()
方法可以通过可迭代对象将多个元素到列表中
a = [1,2,3,4,5]
print(a)
a.extend('abcde') #把字符串的每个字符添加到列表中
print(a)
a.extend([6,7,8,9,10]) #通过列表添加多个元素到列表 a
print(a)
运行效果如下:
insert()
方法可以按照索引插入元素
t = ['a','c','d','e']
print(t)
t.insert(1,'b') #在索引 1 的位置插入元素 'b'
print(t)
运行效果如下:
4.5 列表元素的删除
pop删除指定索引元素
pop()
方法是列表的内置方法,有个可选参数索引( index )默认是 -1,也就是说默认删除最后一个元素,我们也可以设定需要删除的元素索引。
pop()
方法在删除元素后会返回删除的元素。
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
print(letters)
letters.pop() #默认删除最后一个元素
print(letters)
letters.pop(3) #指定索引,索引从0开始,也就是删除第 4 个元素
运行效果如下:
remove()
根据元素值删除
remove()
方法是根据元素的值进行删除,所以必须指定要删除的元素。remove()
方法删除之后不会返回删除的元素,这一点与 pop()
方法不同。
a = [1, 2, 3, 4, '5', 6, 7, '8', 9]
print(a)
a.remove(2) #删除元素 2
print(a)
a.remove('8') #删除元素 '8'
print(a)
运行效果如下:
clear()
方法会清空列表
a = [1, 2, 3, 4, '5', 6, 7, '8', 9]
a.clear()
a
运行效果如下:
del
语句 根据索引删除但不返回值
del
语句和 pop()
方法一样,也是使用索引进行删除元素,不过 del
语句不会返回删除的元素。 del
语句还可以删除切片甚至删除整个列表,这一点 pop()
方法就不支持。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(a)
del a[-1] #删除最后一个元素
print(a)
del a[2:5] #删除切片[2:5]
print(a)
del a[:] #删除列表中全部元素
print(a)
del a #删除列表
print(a)
运行效果如下:
4.6 列表的修改
列表元素的修改
列表可以通过索引或切片赋值改变列表元素,甚至清空整个列表。
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
print(letters)
letters[0] = 'A' #通过索引将第一个元素修改为 'A'
print(letters)
letters[2:5] = ['C', 'D', 'E'] #通过切片对第 3、4、5 个元素进行修改
print(letters)
letters[5:] = [] #将第 6 个之后的元素清空
print(letters)
letters[:] = [] #将整个列表清空
print(letters)
运行效果如下:
4.7 列表排序
- 内置方法
sort
可以实现对列表的排序。
ord() 函数是 chr() 函数(对于 8 位的 ASCII 字符串)的配对函数
它以一个字符串(Unicode 字符)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值。
letters = ['a','aa','B','cc','b','A','bb','c']
letters.sort() #默认按照 Unicode 数值排序,数值越小越靠前
letters
ord('A') # 65
ord('B') # 66
ord('a') # 97
ord('b') # 98
- 可选参数
reverse
默认 Flase ,如果设置为 True 就是反向排序。
letters = ['a','aa','B','cc','b','A','bb','c']
letters.sort(reverse=True)
letters
运行效果如下:
- 另外还有一个可选参数 key 可以实现更复杂的排序。
letters = ['a','aa','B','cc','b','A','bb','c']
letters.sort(key=str.upper) #按照大写字母的形式排序
letters
letters.sort(key=str.lower) #按照小写字母的形式排序
letters
letters.sort(key=len) #按照元素的长度排序,元素必须是可迭代对象
letters
运行效果如下:
reverse()
方法可以实现对列表 x 的翻转,与切片 x[::-1] 类似,不过切片不会修改原列表,所以更推荐使用切片。
letters = ['a','aa','B','cc','b','A','bb','c']
print(letters)
letters[::-1] #翻转之后的结果,如果有需要,可以赋值给其他变量
print(letters) #原列表没有改变
letters.reverse()
print(letters) #原列表已改变
所以reverse()
方法翻转改变了列表,还是切片好,不会改变原来的列表。
4.8 列表的查询
通过内置方法 count()
查看元素出现的次数
fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
fruits.count('apple')
fruits.count('tangerine')
运行效果如下:
index()
返回列表中第一个值为 x 的元素的索引值。
通过内置方法 index()
返回列表中第一个值为 x 的元素的索引值。未找到指定元素时,触发 ValueError
异常。
可选参数 start 和 end 是切片符号,用于将搜索限制为列表的特定子序列。但返回的索引仍然是基于整个序列计算的。
fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
fruits.index('banana')
fruits.index('banana', 4) #从第 5 个元素开始寻找
运行效果如下:
4.9 嵌套列表
嵌套列表就是在列表中包含列表。跟索引一样从0开始,比如下面是0,1,2
a = [[1,2,3],[4,5,6],[7,8,9]]
a[0]
a[1]
a[0][0]
a[2][1]
运行效果如下:
4.10 列表的运算符
列表和字符串、元组一样,也是支持很多运算符。
print([1,2,3] + [4,5]) # + 运算符实现列表合并
print([1,2,3] * 3) # * 运算符实现重复
print(3 in [1,2,3]) # in 运算符判断字符是否在列表中
print(3 not in [1,2,3]) # not in 运算符
运行效果如下:
5. 集合
集合(set
)是一个 无序的不重复元素序列
。满足数学上集合的三大属性 确定性
、互异性
、无序性
。常见的用途包括成员检测、从序列中去除重复项以及数学中的集合类计算,例如交集、并集、差集与对称差集等等。
前面我们提到过,集合是 可变数据类型
,我们再来验证一下:
letters = {'a','b','c'}
print(letters)
print(type(letters),id(letters))
letters.add('d') #增加一个元素 'd'
print(letters)
print(type(letters),id(letters))
运行效果如下:
可以看到,我们通过内置方法给集合新增了一个元素,但内存地址没有发生改变,证明了集合是可变数据类型。
5.1 集合的创建
使用花括号内以逗号分隔元素的方式
a = {'jack', 'sjoerd'}
print(a)
type(a)
运行效果如下:
使用集合推导式
a = {c for c in 'abracadabra'} #集合在创建时会自动去掉重复元素
print(a)
type(a)
运行效果如下:
使用类型构造器 set()
创建集合
a = set() #可以创建空集合,不能用 {} 创建。
print(a)
type(a)
b = {} #这样创建的是字典,我们下一节会讲
type(b)
c = set('foobar') #通过可迭代对象创建集合,会自动去重
print(c)
type(c)
运行效果如下:
5.2 集合添加元素
使用 add()
方法新增元素
letters = {'a','b','c'}
print(letters)
letters.add('d') #新增一个元素 'd'
print(letters)
运行效果如下:
使用 update()
方法可以将可迭代对象中的元素添加到集合中
letters = {'a','b','c'}
print(letters)
letters.update('defg') #从字符串中添加
letters
letters.update(['x','y','z']) #从列表中添加
letters
运行效果如下:
集合的无序性—添加元素顺序随机
因为集合的无序性,我们可以发现,添加的元素顺序非常随机。
5.3 集合删除元素
因为集合的无序性,所以它不存在切片索引的功能
,此处我们将演示几种删除元素的方法。
remove()
方法会删除指定的元素,如果元素不存在就会报错。
letters = {'a','b','c'}
letters.remove('a') #删除元素 'a'
letters
letters.remove('d') #元素不存在会报错
运行效果如下:
discard()
方法和 remove()
方法类似,不过当遇到不存在的元素时不会报错。
letters = {'a','b','c'}
letters.discard('a') #删除元素 'a'
letters
letters.discard('d') #元素不存在不会报错
letters
运行效果如下:
pop()
方法会随机删除元素。
letters = {'a','b','c','d','e','f'}
letters
letters.pop() #随机删除元素
letters
letters.pop() #随机删除元素
letters
运行效果如下:
clear()
方法会清空全部元素
letters = {'a','b','c','d','e','f'}
letters
letters.clear() #清空元素
letters
运行效果如下:
del
语句可以删除整个集合
前面我们使用 del
语句可以通过索引切片删除列表的元素,但因为集合的无序性,所以不存在索引切片的概念。但我们依然可以用 del
删除整个集合。
letters = {'a','b','c','d','e','f'}
del letters
letters
运行效果如下:
可以看到,删除之后就无法再访问了。
5.4 交集
交集是两个集合的公有部分。
intersection
方法
a = {'a', 'r', 'b', 'c', 'd'}
b = {'a', 'l', 'c', 'm', 'z'}
a.intersection(b)
b.intersection(a)
运行效果如下:
&
运算符
a = {'a', 'r', 'b', 'c', 'd'}
b = {'a', 'l', 'c', 'm', 'z'}
a & b
b & a
运行效果如下:
5.5 并集
并集是合并两个集合。
union()
方法
a = {'a', 'r', 'b', 'c', 'd'}
b = {'a', 'l', 'c', 'm', 'z'}
a.union(b)
b.union(a)
运行效果如下:
|
运算符
a = {'a', 'r', 'b', 'c', 'd'}
b = {'a', 'l', 'c', 'm', 'z'}
a | b
b | a
运行效果如下:
需要注意的是,求并集使用
|
运算符,不能使用+
。
5.6 差集
两个集合 A 和 B,所有属于 A 且不属于 B 的元素构成的集合,称为 A 与 B 的差集(A - B)。
根据概念,我们知道两个求差集是有先后顺序的,A 与 B 的差集
和 B 与 A 的差集
就属于两回事。
difference()
方法
a = {'a', 'r', 'b', 'c', 'd'}
b = {'a', 'l', 'c', 'm', 'z'}
print(a.difference(b)) #a 与 b 的差集
print(b.difference(a)) #b 与 a 的差集
运行效果如下:
-
运算符
a = {'a', 'r', 'b', 'c', 'd'}
b = {'a', 'l', 'c', 'm', 'z'}
print(a - b) #a 与 b 的差集
print(b - a) #b 与 a 的差集
运行效果如下:
5.7 列表去重
我们知道,集合具有互异性,通俗来说就是唯一性,不会出现重复的元素,所以我们就可以使用集合给列表去重。
a = [1,2,3,2,5,3,2,1]
b = set(a) #将列表转换为集合
c = list(b) #将集合转换回列表
print(c)
运行效果如下:
总结
本节我们介绍了集合增删元素和数学上交并差在 Python 的实现,最后还提到集合可以给列表去重,需要注意的是,集合和字符串、元组、列表相比,集合具有无序性,所以没有索引和切片。
6 字典
前面我们学习过的字符串、元组、列表都是使用从 0 开始的整数作为索引,而字典以键(key)
为索引,键通常是字符串或数字,也可以是其他任意不可变类型。
字典中每一个 元素
都是一个 key
和一个 value
的组合。我们可以把字典理解为 键值对
的集合,字典的键必须是唯一的。
从 Python 3.6 开始,dict 对象会保持插入时的顺序,在 Python 3.7 中正式宣布该特性成为 Python 语言官方规范的一部分。我们环境目前使用的是 Python 3.8 版本,自然也是支持该特性的。
字典是 可变数据类型
,我们仍像之前一样,进行验证。
age = {'James':23, 'Leonard':25, 'Antetokounmpo':32, 'Durant':24} #这是一个字典
print(age)
print(type(age),id(age))
age['Harden'] = 19 #字典增加元素
print(age)
print(type(age),id(age))
运行效果如下:
6.1 字典的创建
在花括号({}
)内以逗号分隔 键:值
对的方式
a = {} #空字典的创建
print(a)
type(a)
b = {'jack': 4098, 'sjoerd': 4127}
print(b)
type(b)
运行效果如下:
使用字典推导式
a = {x: x ** 2 for x in range(10)}
print(a)
type(a)
运行效果如下:
使用类型构造器 dict()
创建字典
下面的例子中,a
是使用 {}
创建的字典,其他都是通过 dict()
构造函数创建的。其中 s
创建了一个空字典,b
直接用关键字参数指定键值对。
s = dict() #空字典
print(s)
type(s)
a = {'one': 1, 'two': 2, 'three': 3}
b = dict(one=1, two=2, three=3)
c = dict([('two', 2), ('one', 1), ('three', 3)])
d = dict({'three': 3, 'one': 1, 'two': 2})
e = dict({'one': 1, 'three': 3}, two=2)
print(a == b == c == d == e) # a、b、c、d、e 都一样
print(b)
type(b)
运行效果如下:
6.2 字典的查询
我们可以通过 d[key]
的方式查询字典 d
中以 key
为键的项的值。
a = {'one': 1, 'two': 2, 'three': 3}
a['one']
a['two']
运行效果如下:
正常情况下,当我们要查询的键(key
)存在于字典中的时候,上面的查询方式没有问题。但当不存在时,就会抛出 KeyError
异常。
a = {'one': 1, 'two': 2, 'three': 3}
a['four'] #不存在会抛出异常
运行效果如下:
基于上面的原因,我们更推荐使用字典的内置方法 get()
,该方法在查询时遇到不存在的 key
不会报错,而是会默认返回 None
,我们也可以自行定制返回值。
a = {'one': 1, 'two': 2, 'three': 3}
a.get('four') #key 不存在不会报错
a.get('four','这个值不存在') #自定义 key 不存在时的返回值
运行效果如下:
6.3 字典元素的增加和修改
在字典中 增加元素
和 修改元素
的代码其实是相同的,只需要为字典中某一个 key 进行赋值,区别在于:
- 如果此时 key 存在,则判断为你在修改元素,更新该
key
对应的value
值 - 如果不存在,则判断为你在添加元素,向字典中增加该
key: value
键值对,从 Python 3.6 开始,Python 会保持元素插入顺序,新的元素会在字典末尾。
a = {'one': 1, 'two': 2, 'three': 3}
a['one'] = '一' #修改元素
print(a)
a['four'] = 4 #添加元素到末尾
print(a)
运行效果如下:
6.4 字典的删除
pop(key[, default])
方法
pop(key[, default])
方法在 key
存在于字典时会删除并返回对应的值(value
);key
不存在时返回 default
,没有设置 default
会发生 KeyError
异常。
a = {'one': 1, 'two': 2, 'three': 3}
a.pop('one') #删除会返回 'one' 对应的值
print(a)
a.pop('four','您在删除不存在的内容') #设置 default
a.pop('four') #未设置 default,当删除不存在的 key 时会报错
运行效果如下:
popitem()
方法
popitem()
方法会从字典中删除并返回一个 (键, 值)
元组。因为从 Python 3.6 开始,dict 对象会保持插入时的顺序,所以该方法保持 后进先出 的删除顺序,当字典为空时会发生 KeyError
异常。
a = {'one': 1, 'two': 2, 'three': 3}
a.popitem()
a.popitem()
a.popitem()
print(a) #此时字典已空
a.popitem() #空字典继续删除会报错
运行效果如下:
del
语句需要指定 字典名
和需要删除的 key
值,key
不存在时发生 KeyError
异常。
a = {'one': 1, 'two': 2, 'three': 3}
del a['one']
print(a)
del a['four'] #删除不存在的内容
运行效果如下:
clear()
清空字典
a = {'one': 1, 'two': 2, 'three': 3}
a.clear()
print(a)
运行效果如下:
6.5 字典视图对象
a.keys() #由字典的键(key)组成
a.values() #由字典的值(value)组成
a.items() #由字典项 ((键, 值) 对) 组成
运行效果如下:
因为字典视图对象是可迭代的,所以可以通过 list()
、set()
、tuple()
等构造函数将其转换成对应的类型,然后就可以进行切片索引之类的操作。
a = {'one': 1, 'two': 2, 'three': 3}
b = a.keys()
list(b) #转换成列表
set(b) #转换成集合
tuple(b) #转换成元组
运行效果如下:
7 本章总结:
在 Python 中,数据类型分为不可变数据类型和可变数据类型。
- 不可变数据类型:当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称不可变数据类型。数字、字符串、元组 属于不可变数据类型。
-
数字
- 数字类型分为整数类型(int)、浮点数类型(float)、复数类型(complex)
- 布尔类型(bool)是整型的子类型,由两个常量对象 True 和 False 组成,它们用来表示逻辑上的真和假。
- 浮点数类型是使用 C 语言的 double 类型来实现,可以近似表示数学中的实数。
- decimal 模块可以实现快速正确的十进制浮点数计算。
- 复数由实数部分和虚数部分构成,可以用 a + bj,或者 complex(a,b) 表示,复数的实部 a 和虚部 b 都是浮点型。
- Python 支持非常丰富的数学运算。
-
字符串
- 字符串是 Python 中最常用的数据类型。我们一般使用单引号('...') 或双引号( "..." )来创建字符串。我们也可以使用 str() 创建一个空字符串。
- 字符串、元组、列表、集合都支持从 0 开始的数字索引。
- 字符串切片的语法:
string[start:end:step]
f-string
是 Python 在 Python 3.6 引入的格式化方案,是在普通字符串前面加上f
或F
,然后在字符串中使用大括号({}
)引入变量或表达式。另外还有format()
格式化和%
格式化。- 三引号的字符串可以跨越多行,而且可以将所有的空白字符都包含在该字符串中。如果有保持样式的需求,那么就需要使用三引号。
- 字符串支持
+
连接运算符、*
重复运算符等。
-
元组
- 元组(tuple)由多个用逗号隔开的值组成,支持索引和切片。
- 元组支持
+
连接运算符、*
重复运算符等。 - 创建元组时,
a = 1,2,3
是元组打包
,我们使用逆操作实现元组解包
。 len()
函数可以统计元组中元素的个数max()
函数可以返回元组中元素最大值。min()
函数可以返回元组中元素最小值。
- 可变数据类型:当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称可变数据类型。列表、集合、字典属于可变数据类型。
-
列表
- 列表(list)是方括号([])内用逗号分隔的一组值,列表可以包含不同类型的元素。
- 和字符串、元组一样,列表也支持索引和切片,支持多个运算符操作。
- 添加元素的方法有:
append()
、extend()
、insert()
- 删除元素的方法有:
pop()
、remove()
、clear()
以及del
语句 - 列表可以通过索引或切片赋值从而改变列表元素
-
集合
- 集合(set)是一个无序的不重复元素序列,满足数学上集合的三大特性
确定性
、互异性
、无序性
。 - 因为集合的
无序性
,所以集合不支持索引和切片。 - 集合添加元素可以通过
add()
方法和update()
方法 - 集合删除元素可以通过
remove()
方法、discard
方法、pop()
方法、clear()
方法以及del
语句 - 集合支持数学上的交集(
&
)、差集(-
)、并集(|
)等运算。 - 可以通过将其他数据类型先转换成集合,然后再转换回去,实现去重操作。
- 集合(set)是一个无序的不重复元素序列,满足数学上集合的三大特性
-
字典
- 字典(dict) 是一种常用的 Python 內置数据类型。字符串、元组、列表都是使用从 0 开始的整数作为索引,而字典以键(
key
)为索引,键通常是字符串或数字,也可以是其他任意不可变类型。字典中每一个 元素 都是一个key
和一个value
的组合。我们可以把字典理解为 键值对 的集合,字典的键必须是唯一的。 - 从 Python 3.6 开始,dict 对象会保持插入时的顺序,在 Python 3.7 中正式宣布该特性成为 Python 语言官方规范的一部分。
- 我们可以通过
d[key]
的方式查询字典 d 中以 key 为键的项的值,但 key 不存在时会报错,更推荐使用字典的内置方法get()
- 在字典中
增加元素
和修改元素
的代码其实是相同的,只需要为字典中某一个 key 进行赋值。key
存在,就是更新该 key 对应的 value 值;key
如果不存在,则会添加该元素。 pop(key[, default])
方法在key
存在于字典时会删除并返回对应的值(value
);key
不存在时返回default
,没有设置default
会发生KeyError
异常。popitem()
方法会从字典中删除并返回一个(键, 值)
元组。因为从 Python 3.6 开始,dict 对象会保持插入时的顺序,所以该方法保持后进先出
的删除顺序,当字典为空时会发生KeyError
异常。- 由
dict.keys()
,dict.values()
和dict.items()
所返回的对象称为视图对象。 该对象提供字典条目的一个动态视图,当字典改变时,视图也会相应改变。
- 字典(dict) 是一种常用的 Python 內置数据类型。字符串、元组、列表都是使用从 0 开始的整数作为索引,而字典以键(