三、数据类型
3.1 数据类型
3.1.1 数字类型int和float
- 数字类型即变量的值,如age=18,18就是我们保存的值;
- 变量是用来反映/保存状态以及状态变化的,针对不同的状态应该用不同的数据去标识;
- 数字类型只能存储一个值,是不可变类型(不可变类型可以哈希,后面的章节会讲解哈希)
3.1.2 int类型常用的方法
- bin()、oct()、hex()在进制转换中经常用到;
print(bin(3)) # 十进制转成二进制,0b11
print(oct(8)) # 十进制转成八进制,0o10
print(hen(16)) # 十进制转成十六进制,0x10
- 在进行用户交互程序的时候常用.isdigit()(该函数的功能是判断字符串是否全部只由数字组成,如果是,返回True,否则返回False)判断用户输入是不是数字来进行下一步操作。这样避免了程序出错。但是需要注意用户输入的内容默认是字符串,判断一个字符串是否是数字,可以使用下面的方法。
age = input("your age>>:")
if age.isdigit():
age = int(age)
age += 1
print(age)
3.1.3 Python其它数字类型(了解)
-
#int(整型)
- 在32位机器上,整数的位数为32位,取值范围为 − 2 31 -2^{31} −231到 2 31 − 1 2^{31}-1 231−1,即-2147483648到2147483647。
- 在64位机器上,整数的位数为64位,取值范围为 − 2 63 -2^{63} −263到 2 63 − 1 2^{63}-1 263−1,即-9223372036854775808到9223372036854775807。
-
#long(长整型)
- 和C语言不同,Python的长整型没有指定位宽,即Python没有限制长整数数值的大小。
- 自从Python2.2起,如果整数发生溢出,Python会自动将整数数据转换为长整数,所以在长整型数据之后不加字符long;
- 在Python3里不再有long类型,全都是int。
-
#complex(复数型)
-和数学上的复数是一样的。
a = 2 ** 64 # 长整型,但是数据类型仍然是int型
x = 1-2j # 复数
x.img = 2 # 复数的虚部为2,使用.ing求复数的虚部
x.real = 1 # 复数的实部为1,使用.real求复数的实部
3.2 字符串类型
3.2.1 字符串类型介绍
- 在python中,加了引号的字符就是字符串类型,用于标识:描述性的内容,如姓名,性别,国籍,种族,定义形式;
- 字符串格式化:
name = input('请输入名字>>:')
print('你好,%s' % name) # %s可以理解为占位符,在输出时会使用字符串后面的%后面的变量的值进行替换
3.2.2 单引号,双引号和三引号的区别
- 单引号、双引号是没有区别的,但是当字符串中用到单引号时,整个字符串需要用到双引号;
- 用到多行字符串时必须使用多引号;
msg = "I'm 18 years old!"
mes =
'''
今天我想写首小诗,
歌颂我的同桌。
你看他那乌黑的短发,
好像一只炸毛鸡。
'''
3.2.3 字符串的拼接
- 字符串能进行相加和相乘的操作;相加是将两个字符串拼接起来;相乘是将一个字符串进行多次复制然后拼接起来;
name = 'albert'
age = '18'
name + age => 'albert18'
name*5 => 'albertalbertalbertalbertalbert'
注意:
- 字符串1+字符串2,并不会在字符串1的基础上加字符串3。而是申请一个全新的内存空间存入字符串1+字符串2;
- 只能进行字符串+字符串,不能字符串+其它类型数据;
字符串类型只能存储一个值,是一个不可变类型,可以哈希;
3.3.4 字符串类型常用方法
(1)按照索引取值
字符串是不可变类型,并不能改变字符串的值,取值时最多可以有三个参数,分别是起始位置,结束位置和步长。可以正向取值或反向取值。步长为-1表示从最后一个元素开始取值。步长可以为负数。
hobbies = 'music basketball'
hobbies[0]
hobbies[0:5]
hobbies[0:5:2] # 从第0个元素到第4个元素,隔一个元素取一次值
hobbies[0:5:-2] # 取不到元素,因为从第0个元素到第4个元素,逆序隔一个元素取一次值
hobbies[11:5:-2] # 从第11个元素到第6个元素,逆序隔一个元素取一次值
hobbies[-1] # 取倒数第一个字符
(2)长度运算
len('name') # 用来求string类型,列表等的长度
(3)成员运算
print('a' in 'Albert') # 判断a是否在Albert中,在则返回True,否则返回False
# 输出为False
print('a' not in 'Albert')
# 输出为True
(4)移除空白
print(' name'.lstrip()) # 移除左边空白
print('name '.rstrip()) # 移除右边空白
print(' naem '.strip()) # 移除两端空白
(5)切分
切分的作用是根据给定的切分规则将一段字符串切分开,并以列表的形式返回;
print('kobe 24 lakers'.split(' ')) # 返回为['kobe', '24', 'lakers']
print('kobe/24/lakers'.split('/',1)) # 1表示仅切分一次,返回为['kobe', '24/lakers']
print('kobe/24/lakers'.rsplit('/',1)) # 表示从右往左进行切分
(6)组合
print('a'.join('1234')) # 输出为1a2a3a4
tag = ' '
print(tag.join(['I','say','hello','world'])) # 输出为I say hello world
(7)替换
print('abc name id'.replace('a','card')) # 将前面字符串中的a全部替换为'card'
3.3 列表
3.3.1 列表类型基本介绍
在[]内用括号分割,可以存放n个任意类型的值,用于标识:存储多个值的情况。
students = ['albert', 'james', 'kd']
列表可以存储多个值,是有序的,是可变类型·,不可以哈希;
3.3.2 列表类型常用的方法
(1)添加元素
- append方法,在列表最后追加元素
l1 = ['a', 'b', 'c', 'd', ]
l1.append('e') # 输出为['a', 'b', 'c', 'd', 'e']
l1.append(['a', 'b', 'c', 'd', ]) # 输出为['a', 'b', 'c', 'd', 'e', ['a', 'b', 'c', 'd']]
- insert方法,在列表中插入元素
l1 = ['a', 'b', 'c', 'd', ]
l1.insert(3, 'x') # 输出为['a', 'b', 'c', 'x', 'd']
- extend方法,在列表中同时插入多个元素,extend方法使用和append方法的区别(append是整体添加,extend是逐个添加)
l1 = ['a', 'b', 'c', 'd', ]
l1.append(['a', 'b', 'c', 'd', ]) # 输出为['a', 'b', 'c', 'd', 'e', ['a', 'b', 'c', 'd']]
l1 = ['a', 'b', 'c', 'd', ]
l1.extend(['a', 'b', 'c', 'd', ]) # 输出为['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']
- extend在执行添加的时候,被传入的参数必须是可迭代对象,这样通过迭代就解决了同时传入多个参数的问题。
l1 = ['a', 'b', 'c', 'd', ]
l1.extend('abc') # 输出为['a', 'b', 'c', 'd', 'a', 'b', 'c']
l1 = ['a', 'b', 'c', 'd', ]
l1.append('abc') # 输出为['a', 'b', 'c', 'd', 'a', 'b', 'c', 'abc']
l1 = ['a', 'b', 'c', 'd', ]
l1.extend('a') # 输出为['a', 'b', 'c', 'd', 'a', 'b', 'c', 'a']
(2)删除元素
- pop删除,有返回值,默认删除列表中最后一个,指定删除索引值;
l1 = [1, 2, 3, 4, 5, 6, ]
print(l1.pop()) # 删除列表中的某个元素,默认是最后一个元素,这个是有返回值的,返回值为6;
print(l1) # 输出为[1, 2, 3, 4, 5]
print(l1.pop(2)) # 删除索引为2的地方的值,返回值为3
print(l1) # 输出为[1, 2, 4, 5]
- remove删除,没有返回值,没有默认值,指定被删除的元素,不是指定索引,是指定的值;
l1 = [1, 2, 3, 4, 5, 6, ]
print(l1.remove(2)) # 删除列表中值为2的数据
print(l1) # 输出为[1, 3, 4, 5, 6]
- clear删除,保留列表名称,清空里面的值;
l1 = [1, 2, 3, 4, 5, 6, ]
l1.clear()
print(l1) # 输出为[]
- del删除,通用删除,但是一般不用;
l1 = [1, 2, 3, 4, 5, 6, ]
del l1[2] # 删除索引为2的内存存储的值,输出为[1, 2, 4, 5, 6]
del l1
print(l1) # 输出为NameError: name 'l1' is not defined
(3)更改元素
- 注意与insert插入的不同,都是以原来的位置为参考,insert是挤开,本质是添加,而这里是替换;
l1 = [1, 2, 3, 4, 5, 6, ]
l1[2] = 4
print(l1) # 输出为[1, 2, 4, 4, 5, 6]
(4)查找元素
- 按照索引或者指定列表中的元素查找
l1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
print(l1.index('a')) # 返回'a'在l1的索引值
print(l1.index('b', 1, 4)) # 检索的起始位置和终止位置
- 把列表分段查找
l1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
a = int(len(l1)/2)
print(l1[:a]) # 输出为['a', 'b', 'c']
print(l1[a:]) # 输出为['d', 'e', 'f', 'g']
- 使用enumerate对列表枚举
l1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
for i, x in enumerate(l1, 100): # 100的意思是将100指定为枚举开始的位置
print(i, x) # i是索引的地址,x是对应的列表中的值
# 输出为
100 a
101 b
102 c
103 d
104 e
105 f
106 g
(5)统计长度
print(len([1,2,3,4,]))
(6)统计元素个数
print(['a','b'].count('a'))
(7)排序
- resverse 反序排序
l1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
l1.reverse()
print(l1) # 输出为['g', 'f', 'e', 'd', 'c', 'b', 'a']
- sort 按照ASCII码来进行排序
l1 = ['a', '1', 'b', 'c', 'd', 'e', 'f', 'g']
l1.sort()
print(l1) # 输出为['1', 'a', 'b', 'c', 'd', 'e', 'f', 'g']
l1.sort(reverse=True) # 输出为['g', 'f', 'e', 'd', 'c', 'b', 'a', '1']
print(l1)
(8)复制列表
l1 = ['a', '1', 'b', 'c', 'd', 'e', 'f', 'g']
print(l1.copy()) # 输出为['a', '1', 'b', 'c', 'd', 'e', 'f', 'g']
(9)Python中的赋值、浅拷贝和深拷贝的区别
- 赋值:对于复制的操作,最简单的就是赋值,指的是新建一个对象的引用,新建目标对象与原来的目标对象指向同一个内存地址。因而始终保持一致。
l1 = [1, 2, 3, 4, 5, [6, 7, 8, ]]
l2 = l1
l1.append(9)
print(l1) # 输出为[1, 2, 3, 4, 5, [6, 7, 8], 9]
print(l2) # 输出为[1, 2, 3, 4, 5, [6, 7, 8], 9]
l1[5][0] = 10
print(l1) # 输出为[1, 2, 3, 4, 5, [10, 7, 8], 9]
print(l2) # 输出为[1, 2, 3, 4, 5, [10, 7, 8], 9]
l1[5] = 10
print(l1) # 输出为[1, 2, 3, 4, 5, 10, 9]
print(l2) # 输出为[1, 2, 3, 4, 5, 10, 9]
- 浅拷贝:浅拷贝顾名思义就是拷贝的比较浅,可以把赋值认为是新建了一个对象的引用,把原来被对象内存空间的数据指向新的变量,这时同一块内存空间指向两个变量,浅拷贝和赋值不同。既然是拷贝,那么就是要开辟一块新的内存空间,复制的是原来被拷贝对象内多个元素对象的引用,有几个元素对象就赋值几个元素对象的引用。因此,被浅拷贝对象内的元素改变,会引起浅拷贝对象内元素的改变;被拷贝对象添加元素,拷贝对象不再添加元素(因为没有一个新的引用);被拷贝对象删除元素,拷贝对象也删除元素(元素搜已经删除了,虽然引用存在,但是并没有什么用)。
- 深拷贝:深拷贝其实与浅拷贝有本质的区别,它不会复制任何的引用,对象内的所有元素,子元素,孙子元素,重孙元素,曾孙元素的数据都是复制而来。它的实现原理是递归,只要任意元素内仍然有子元素,就会复制子元素的数据放到新的内存地址。既然这样,在使用深拷贝后,被拷贝对象的改变,不会引起拷贝对象的任何改变。
复制与深浅拷贝的总结:
- 赋值:新建一个原来对象内存地址的引用,不开辟新的内存空间;
- 浅拷贝:新建多个原来对象内一级子元素内存地址的引用,开辟新的内存地址;
- 深拷贝:复制原来对象内的所有N级子元素的数据,开辟新的内存空间;
3.4 元组
- 与列表类型相比,非常类似只不过把[]变成(),作用是用于存储多个值,对比列表来说,元组不可变(是可以当做字典的key的),不可改变,主要是用来读;
- 元组可以存储多个值,是有序的,是不可变类型,可以哈希。元组常用的方法,可以参考列表常用方法,需要注意的是,元组只能取值,不能改变元组的值。
3.5 字典
3.5.1 字典类型基本介绍
字典用于存放一个人的信息:姓名,性别,年龄,很明显是多个值,既然是存多个值,我们完全可以基于刚刚学习的列表去存放,如下:
info = ['albert','male',18]
既然如此,为什么还需要字典呢?定义列表的目的不单单是为了存储,还要考虑取值,但是如果想取出这个人的年龄,可以用info[2]。
但是这是基于我们已经知道在第3个位置存放的是年龄的前提下,我们才知道索引2对应的是年龄,而这完全只是一种假设,并没有真正意义上规定第三个位置存放的是年龄。于是我们寻求一种,既可以存放多个任意类型的值,又可以硬性规定值的映射关系的类型,这就用到字典。
字典用于标识存储多个值的情况,每个值有唯一一个对应的key,可以更为方便高效地取值,字典的格式定义如下:
# 在{}内用逗号分隔,可以存放多个key:value值,key一般是字符串,value可以是任意类型
info = {'name':'albert','age':18,'sex':18}
字典可以存储多个值,是无序的,是可变类型,不可哈希。
3.5.2 字典类型常用的方法
(1)增加元素
通过键值对
l1 = {'name':'albert', 'age':18,'gender':'male'}
l1['hobbies']='music'
print(l1)
# 输出为{'name': 'albert', 'age': 18, 'gender': 'male', 'hobbies': 'music'}
用fromkeys构造一个字典
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
a = l1.fromkeys(l1, 'I am Albert')
print(a)
# {'name': 'I am Albert', 'age': 'I am Albert', 'gebder': 'I am Albert'}
b = dict.fromkeys('name')
print(b)
# {'n': None, 'a': None, 'm': None, 'e': None}
b = dict.fromkeys('e')
print(b)
# {'e': None}
b = dict.fromkeys(1) # 报错,数字类型不可迭代
print(b)
# TypeError: 'int' object is not iterable
b = dict.fromkeys([1, 2, 3, ])
print(b)
# {1: None, 2: None, 3: None}
(2)删除元素
del 通过字典的key删除
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
del l1['name']
print(l1)
# {'age': 18, 'gebder': 'male'}
pop或者popitem删除
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
res = l1.pop('name') # 删除指定key的value,并拿到一个返回值
print(res)
# albert
print(l1)
# {'age': 18, 'gebder': 'male'}
res2 = l1.popitem() # 随机返回并删除字典中的一对键和值(一般删除末尾对)
# 如果字典已经为空,却调用了此方法,就报出KeyError异常
print(res2)
# ('gebder', 'male')
print(l1)
# {'age': 18}
(3)更改元素
通过键值对的方式
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
l1['name'] = '马一特'
print(l1)
# {'name': '马一特', 'age': 18, 'gebder': 'male'}
通过setdefault或者update操作,两者使用和区别如下:
- setdefault只添加不修改
d1 = {'name': 'albert', 'age': 18, }
d1.setdefault('name', 'Albert')
d1.setdefault('gender', 'male')
print(d1)
# {'name': 'albert', 'age': 18, 'gender': 'male'}
- update既添加也修改
d1 = {'name': 'albert', 'age': 18, }
d1.update({'name': 'Albert', 'gender': 'male'})
print(d1)
# {'name': 'Albert', 'age': 18, 'gender': 'male'}
(4)查找元素
通过键值对查找
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
a = l1['name']
print(a)
# albert
通过get方法查找
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
a = l1.get('hobbies') # 找不到不报错
print(a)
# None
通过enumerate枚举
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
for a in enumerate(l1):
print(a)
# (0, 'name') (1, 'age') (2, 'gebder')
通过.key(),.values(),.items()等方法
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
a = l1.keys()
print(a)
# dict_keys(['name', 'age', 'gebder'])
print(list(a)[0])
# name
a = l1.values()
print(a)
# dict_values(['albert', 18, 'male'])
print(list(a)[0])
# albert
a = l1.items()
print(a)
# dict_items([('name', 'albert'), ('age', 18), ('gebder', 'male')])
print(list(a)[0])
# ('name', 'albert')
通过for循环遍历
l1 = {'name': 'albert', 'age': 18, 'gebder': 'male'}
for k,v in l1.items():
print(k,v)
# name albert
# age 18
# gebder male
(5)成员运算与长度运算
参考列表的运算方法,成员运算的依据是字典的key,而不是value,长度运算都可以作为参考的依据。
3.6 集合类型
花括号内,多个元素用逗号分割,用来存储多个值,并且是无序的,那么这多个值不能用来取值,但是可以用来进行去重(比如去掉列表中重复的元素)和关系运算。
集合的元素遵循三个原则:
\space
1:每个元素必须是不可变类型(可作为字典的key);
2:没有重复的元素;
3:无序;
\space
注意集合的目的是将不同值存放到一起,不同集合间用来做关系运算,无需纠结与集合中单个值。
集合类型可以存放多个值,是无序的,是可变类型,不可以哈希。
关系运算练习:
有以下两个集合,piano是报名钢琴课程的学员名字集合,violin是报名小提琴课程的学员名字集合。
piano = {‘albert’, ‘孙悟空’, ‘周星驰’, ‘朱茵’, ‘林志玲’}
violin = {‘猪八戒’, ‘郭德纲’, ‘林忆莲’, ‘周星驰’}
1、求出既报名钢琴又报名小提琴课程的学员名字集合;
2、求出所有报名的学生名字集合;
3、求出只报名钢琴课程的学员名字;
4、求出没有同时报名这两个课程的学员名字集合。
答案:
print(piano & violin)
print(piano | violin)
print(piano - violin)
print(piano ^ violin)
3.7 collections容器数据类型
(1)namedtuple命名元组
from collections import namedtuple
point = namedtuple('p', ['x', 'y']) # p代表名称,x和y代表内容
p = point(1, 2)
print(p)
# p(x=1, y=2)
print(p.x)
# 1
print(p.y)
# 2
(2)deque超级列表
数据结构中比较常用的双向队列在python中可以使用deque实现。
collections容器类型一共有9种,除了上面介绍之外,还有ChainMap链映射,Counter计数字典,OrderedDict,defaultdict,UserDict,UserList,UserString。