第三章 数据类型
3.1 整型(int)
3.1.1 整型的长度
py2中有:int有取值范围,对于32位系统而言:-231~231-1
对于64位系统而言:-263~263-1
超出范围后,py2自动转换成long(长整型)数据。
py3中有:int (int/long)只有int数据.
3.1.2 整除
py2和py3中整除是不一样.
-
py2:整除只保留整数,小数位会舍去.若要保留小数.则在文件头加
from __future__ import division
-
py3整除保留所有.
3.2 布尔(bool)
布尔值就是用于表示真假。True和False。
其他类型转换成布尔值:只有''/0/[]/{}/()/set()转换为bool值为False,其余都是True.
3.3 字符串(str)
字符串是写代码中最常见的 :
- 单引号,如'王飞'
- 双引号,如”王大“
- 三引号,如“”“王小”“”,三引号支持换行。
注意:整型数据可以+和×,字符串数据也可以+和×。如
name='五五开'
new_name=name*3
print(new_name) # '五五开五五开五五开'
python内存中的字符串是按照:unicode 编码存储。对于字符串是不可变数据类型。
3.3.1字符串的格式化
-
字符串格式化的意义,大部分字符过于冗长,使用字符串格式化能大大加快效率,方便程序员调用数据。
-
%s 、 %d、%%
-
red_dad = '大红的爸爸' do = '教学生上课' thing = '%s在操场%s' %(red_dad,do,) print(thing)
-
直接做占位符
temper = '%s在太空中%s' %('等大侠','打飞机',) print(temper) thing = '盖伦,年龄%d,喜欢在池塘里%s' %(15,'打水仗',) print(thing) ##### #s和#d表示的类型不同,前者表示字符串数据,后者表示整型数据。 name = '小明' template = "%s拿出了100%%的力气" %(name,) print(template) ###### %%,为了和字符串格式化做区分,百分号要写成%%形式。
-
name = "我叫{0},年龄:{1}".format('老男孩',73) # 对应的是索引位置
print(name)
name = '我是{x1},爱{xx}'.format_map({'x1':"邓",'xx':18}) #format_map对应的键
print(name)
print(name)
-
格式化补充
# 一般的格式化 msg = '我今年%s岁,叫做%s ,爱好%s' %(25,'邓益新','女') print(msg) msg1 = '我今年{}岁,叫做{} ,爱好是这个{}'.format(25,'邓益新','女') print(msg1 )
字符串格式化补充
# %(关键字)s msg = '我今年%(intt)s岁,叫做%(name)s ' %{'intt':25,'name':'邓益新'} # 只能用字典 print(msg) # v1 = "我是{0},年龄{1}".format('alex',19) v1 = "我是{0},年龄{1}".format(*('alex',19,)) print(v1) # v2 = "我是{name},年龄{age}".format(name='alex',age=18) #关键字传参 v2 = "我是{name},年龄{age}".format(**{'name':'alex','age':18}) print(v2) ########################### msg1 = '我今年{nain}岁,叫做{name} '.format(**{'nain':25,'name':'邓益新',}) msg2 = '我今年{nain}岁,叫做{name}'.format(nain= 25,name= '邓益新',)
3.3.2字符串的方法
字串自己有很多方法,如:
-
大写: upper/isupper
v = 'DEng' v1 = v.upper() # DENG print(v1) v2 = v.isupper() # 判断是否全部是大写 print(v2) # False
-
小写:lower/islower
v = 'yixin' v1 = v.lower() print(v1) v2 = v.islower() # 判断是否全部是小写 print(v2) ############ 了解即可 v = 'ß' #德语大小写的转换 # 将字符串变小写(更牛逼) v1 = v.casefold() print(v1) # ss v2 = v.lower() print(v2) #lower() 方法只对ASCII编码,也就是‘A-Z’有效,对于其他语言(非汉语或英文)中把大写转换为小写的情况只能用 casefold() 方法。
-
判断是否是数字: isdecimal(推荐使用)
v = '1' # v = '二' # v = '②' v1 = v.isdigit() # '1'-> True; '二'-> False; '②' --> True v2 = v.isdecimal() # '1'-> True; '二'-> False; '②' --> False v3 = v.isnumeric() # '1'-> True; '二'-> True; '②' --> True print(v1,v2,v3) # 以后推荐用 isdecimal 判断是否是 10进制的数。 # ############## 应用 ############## v = ['deng','yi','xin'] num = input('请输入序号:') if num.isdecimal(): num = int(num) print(v[num]) else: print('你输入的不是数字')
-
split() ,去空白+ + + 指定字符串
# 注意;该方法只能删除开头或是结尾的字符,不能删除中间部分的字符.类似的有rstip/lstrip,从字符串右端/左端来操作. v1 = "alex " print(v1.strip()) v2 = "alex " # 等价于 Tab键,4个空格 print(v2.strip()) v3 = "alex " # 等价于 换行符 print(v3.strip()) v1 = "dnengyixin" print(v1.strip('dn')) # 输出'engyixi' # 只要头尾包含有指定字符序列中的字符就删除
-
替换 replace
v = 'dengyixin' v1 = v.replace('i','123') print(v1) # dengy123x123n ,从左到右替换所有字符 v = 'dengyixindengyixin' v1 = v.replace('i','123',3) print(v1) # dengy123x123ndengy123xin ,从左到右替换前 3 个字符字符.
-
开头 / 结尾startswith/endswith
v = 'dengyixindengyixin' #判断以``字符开头/结尾 flag1 = v.startswith('de') flag2 = v.endswith('in') print(flag1,flag2) # True True
-
编码encode,把字符串转换成二进制
v = '邓益新' # 解释器读取到内存后,按照unicode编码方式存储 v1 = v.encode('utf-8') print(v1) #输出'邓益新'以utf-8码的二进制 v2 = v1.decode('gbk') print(v2) #报错,编码问题,以什么码写,就用什么码读. # 解码 decode,把二进制转换成字符串
-
join方法
name = 'dengixn' result = "_".join(name) # 循环每个元素,并在元素和元素之间加入'_'。 print(result) # d_e_n_g_i_x_n
-
split
str.split("根据什么东西进行切割",从左到右对前多少个东西进行切割) str.rsplit("根据什么东西进行切割",从右到左对前多少个东西进行切割) name = 'dengixindeng' name_new = name.split('n') #不填数字默认切割所有,从左到右切割. print(name_new) # ['de', 'gixi', 'de', 'g']
3.3 字符串补充
3.3.1字节类型数据bytes
-
str,字符串类型,一般用于内存中做数据操作。
v = 'alex' # unicode编码存储在内存。
-
bytes,字节类型,一般用于数据存储和网络传输。
v = 'alex'.encode('utf-8') # 将字符串转换成字节(由unicode编码转换为utf-8编码) v = 'alex'.encode('gbk') # 将字符串转换成字节(由unicode编码转换为gbk编码)
-
py2和py3字符串类型不同
- py3: str bytes
- py2: unicode str
-
py2和py3字典方法得到的返回值不同
- keys
- py2:列表
- py3:迭代器,可以循环但不可以索引
- values
- py2:列表
- py3:迭代器,可以循环但不可以索引
- items
- py2:列表
- py3:迭代器,可以循环但不可以索引
- keys
-
map/filter
- py2:返回列表
- py3:返回迭代器,可以循环但不可以索引
3.3.2py2 和py 3的五点不同点
答 :
-
默认解释器编码
-
输入输出
-
整数的除法 / int long
-
py3: str bytes
py2: unicode str
-
字典方法得到的东东不同
- keys
- py2:列表
- py3:迭代器,可以循环但不可以索引
- values
- py2:列表
- py3:迭代器,可以循环但不可以索引
- items
- py2:列表
- py3:迭代器,可以循环但不可以索引
- keys
-
map/filter
-
py2:返回列表
-
py3:返回迭代器,可以循环但不可以索引
-
3.4列表
3.4.1列表介绍
users = ["代永进","李林元","邓益新",99,22,88] #表示多个事物,用列表.是有序的,可变类型
3.4.2列表方法
-
append,在列表的最后追加一个元素
users = [] while True: name = input('请输入姓名:') # 利用无限循环添加用户名到列表users users.append(name) print(users)
-
insert,在列表索引位置添加元素
users = ["代永进","李林元","邓益新",99,22,88] users.insert(2,'大笨蛋') # 在列表索引2位置添加'大笨蛋'
-
remove,从左到右删除列表第一个元素
users = ["代永进","李林元","邓益新",99,22,88] users.remove("邓益新") # 从列表中从左到右删除第一个"邓益新",
-
pop,删除列表索引位置元素,可以赋值给一个新变量,得到被删除的值.
users = ["代永进","李林元","邓益新",99,22,"邓益新",88] result = users.pop(2) print(result,users)# 从列表中删除对应索引位置 /邓益新 ['代永进', '李林元', 99, 22, '邓益新', 88]
-
clear,清除列表所有元素
users = ["代永进","李林元","邓益新",99,22,88] users.clear() # 从列表清除所有元素 ,得到[]
-
reverse,反转列表元素
users = ["代永进","李林元","邓益新",99,22,88] users.reverse() print(users) # [88, '邓益新', 22, 99, '邓益新', '李林元', '代永进']
-
sort,从小到大排列列表元素
users = [1,2,3,8,4,6,5,9,0] users.sort() # ()里默认reverse = False print(users) # [0, 1, 2, 3, 4, 5, 6, 8, 9] users.sort(reverse = True) # 从大到下排列列表元素
-
extent.用于在列表末尾一次性追加另一个序列中的多个值
users = ["代永进","李林元","邓益新",99,22,88] users.extend('deng') users.extend([11,22,33]) users.extend((44,55,66)) users.extend({77,88,99}) print(users) # ['代永进', '李林元', '邓益新', 99, 22, 88, 'd', 'e', 'n', 'g', 11, 22, 33, 44, 55, 66, 88, 99, 77],在后面添加.
3.5元组tuple
3.5.1元组的特点
-
users = ["代永进","李林元","邓益新",99,22,88] # 列表可变类型[] users = ("代永进","李林元","邓益新",99,22,88) # 元组不可变类型()
-
元组没有自己独有的方法.
-
元组可索引,切片,步长, 不可删除,修改 ..
-
注意:元组中的元素(儿子)不可被修改/删除
# 元组可以嵌套,可以有list数据,多重嵌套 v1 = (11,22,33,(44,55,66),(11,2,(99,88,),[666,999,888],["代永进","李林元","邓益新"])) 注意:元组中嵌套列表, 元组:只读列表,可循环查询,可切片。儿子不能改,孙子(列表的元素)可能可以改 v2 = (1,2,3,'alex',[2,3,4,'abnowen'],'deng') v2[3] = 666 # 错误 v2[4][3] = 123 #正确 print(v2) # (1, 2, 3, 'alex', [2, 3, 4, 123], 'deng')
3.6字典dict
3.6.1字典介绍
-
是一种可变容器模型,且可存储任意类型对象 ,帮助用户去表示一个事物的信息。各种属性。
-
用{}表示,如
d = {key1 : value1, key2 : value2,键:值 } # 键值对 # 键一般是唯一的,如果重复最后的一个键值对会替换前面的。 # 值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组,键不可以是列表和字典。
3.6.2字典方法介绍
-
keys / values / items /
dict = {'Name': 'deng', 'Age':18, 'Class': 'First'} print(dict.keys()) #获取dict中所有键 print(dict.values()) ##获取dict中所有值 print(dict.items()) #获取dict中所有键值对
-
get(key, default=None),获取某键的值,如果字典中不包含该键,就返回得到None或自定义内容
info = {'k1':'v1','k2':'v2'} v1 = info.get('k1') # v1 v2 = info.get('k123456') # None,数据类型,该类型表示空(无任何功能,专门用于提供空值)字典中不存在该键是默认得到None v3 = info.get('k123478','不存在该键') #不存在该键时,可自定义返回的值 print(v1,v2,v3) # v1 None 不存在该键
-
pop(key),删除字典的键值对.如果字典中没有该键,会报错。
info = {'k1':'v1','k2':'v2'} result = info.pop('k1') #返回得到 'v1' print(info) #{'k2':'v2'}
-
.update(), 字典添加元素,可添加多个.
info = {'k1':'v1','k2':'v2'} info.update({22:33}) info.update({'k1':'123456'}) # 没有的键,键值对就添加进去,有的键,键对应的值就更新 print(info) # {'k1': '123456', 'k2': 'v2', 22: 33}
3.7集合set()
3.7.1集合介绍
- 集合无序,元素唯一,不允许重复.
- 用{},为和字典做区分,空集合表示为set(),类似于d = {0,1,2,3,4}或者d = set()
- 引申:
- 其他数据类型的也可以类似表示,如:srt()/list()/tuple()/dict()/int()等等
3.7.2集合方法
-
add,为集合添加单个元素
tiboy = set() tiboy.add('boy') print(tiboy) # tiboy = {1,2,3,4,56,7,8,9,'boy'} 不存在元素就添加.存在该元素集合不变/
-
.update(x), ,添加元素.x 可以是列表,元组,字典
print(tiboy) # update x 可以是列表,元组,字典。 tiboy.update([(1,2,3,4,5,6,7),'deng','yi','xin',1,2,3]) print(tiboy) # {1, 2, 3, 4, 7, 8, 9, 'xin', 'deng', 'yi', 56, (1, 2, 3, 4, 5, 6, 7), 'boy'} 列表/字典/集合不能放在集合中,但元组可以。
-
.discard(x) ,移除集合的元素x,若集合没有x,返回值为None,区别于.remove(x) ,若集合没有x,则会报错。.clear() 清除集合所有元素。
tiboy = {1,2,3,4,56,7,8,9,'boy'} tiboy.discard(1) print(tiboy,t) # {2, 3, 4, 7, 8, 9, 'boy', 56}
-
.intersection() / .union( ) / .difference() /.symmetric_difference(求交集,并集 差集)
A = {1,2,3,4,5,6} B = {5,6,7,8,9,10} 集合1和2的并集 = A.union(B) print(集合1和2的并集) #A∪B 集合1减去2的差集 = A.difference(B) print(集合1减去2的差集) # 集合A-B 集合1和2的交集 = A.intersection(B) print(集合1和2的交集) #A∩B deng123 = A.symmetric_difference(B) print(deng123) # A∪B-A∩B
3.8 公共功能
-
len(),求长度.(排除 int / bool)
- str,求字符的个数.len("deng") = 4 / len("邓益新") = 3
- 对列表/元组/集合,求元素的个数
- 对字典,求键值对的个数
-
索引 ( int / bool /set )
- 从左到右,从0开始,取前不取后.
- str , 'deng'[0] = 'd' / deng'[2] = 'n' /也可以最后一位,以-1为起始.'deng'[-1] = 'g'
- 对列表/元组,类似于字符串,索引对应里面的元素, 因集合无序,不具有索引功能.
- 对字典,索引的是它的键,得到键对应的值. {}[key] = value
-
切片 ( int / bool /set /dict)
- 通过索引取单个元素,切片可以取一片
- str ,'deng'[0:2] = 'den' ,其他列表/元组与此类似.
- 字典 无切片 功能, 集 合 无序,没有切片功能.
-
步长 ( int / bool /set /dict )
- str ,'dengyixin'[::2] = 'dnyxn' 每2个字符取前一个,步长为2.步长为负数,则反转,从右到左切片.
- list / tuple / 都与此类似.
- 字典和集合没有此功能
-
for循环
-
for i in str/list/tuple/set ,都是对里面的元素循环一次
-
for item in dict,这里指的是字典的键.
-
注意:for和while的应用场景:有穷尽优先使用for,无穷尽用while。
name = 'dengxin' for item in name: print(item) # 竖向打印d e n g x i n name = 'dengxin' for item in name: print(item) break # for循环的break语句 print('123') name = 'dengxin' for item in name: print(item) continue # for循环的continue语句 print('123')
-
-
删除del del user[索引] 数字/字符串/布尔值除外
-
-
索引(排除:int/bool)
users = (11,22,33,"老男孩") print(users[0]) print(users[-1])
-
切片(排除:int/bool)
users = (11,22,33,"老男孩") print(users[0:2])
-
步长(排除:int/bool)
users = (11,22,33,"老男孩") print(users[0:2:2])
-
删除(排除:tuple/str/int/bool)
-
修改(排除:tuple/str/int/bool)
-
for循环(排除:int/bool)
users = (11,22,33,"老男孩") for item in users: print(item)
-
len(排除:int/bool)
users = (11,22,33,"老男孩") print(len(users))
-
3.9额外内容
3.9.1判断敏感字符
-
str: 使用in 即可判断
-
list/tuple
list1 = ['alex','oldboy','deng','xin'] if 'deng' in list1: print('含敏感字符') # 同样,对于元组也是这样
-
dict
dict1 = {'k1':'v1','k2':'v2','k3':'v3'} #默认按照键判断 if 'x' in dict1 : # 判断x是否是字典的键。 print('dict1的键包含x') #判断字典的值x #第一种 dict1 = {'k1':'v1','k2':'v2','k3':'v3'} if 'x' in list(dict1.values()): # ,强制转化为list判断x是否是字典的值。 print('dict1的值包含x') #判断字典的值v2 #第二种循环 for v in dict1.values(): if v == 'v2' print('存在') #判断字典的键值对 k2:v2 是否在其中 value = list1.get('k2') if value == 'v2': print('包含')
3.10 嵌套
3.10.1列表嵌套
- 列表可以嵌套多层,int、str、bool、list都可以有
3.10.2元组嵌套
-
元组可以嵌套,可以有list数据,多重嵌套
-
元组和列表可混合嵌套
-
注意:元组中的元素(儿子)不可被修改/删除
# 元组可以嵌套,可以有list数据,多重嵌套 v1 = (11,22,33,(44,55,66),(11,2,(99,88,),[666,999,888],["代永进","李林元","邓益新"])) 注意:元组中嵌套列表, 元组:只读列表,可循环查询,可切片。儿子不能改,孙子(列表的元素)可能可以改 v2 = (1,2,3,'alex',[2,3,4,'abnowen'],'deng') v2[3] = 666 # 错误 v2[4][3] = 123 #正确 print(v2) # (1, 2, 3, 'alex', [2, 3, 4, 123], 'deng')
3.10.3字典嵌套(重点)
-
列表/字典/集合(可变类型) -> 不能放在集合中+不能作为字典的key(unhashable)
-
hash函数,在内部会将值进行哈希算法并得到一个数值(对应内存地址),以后用于快速查找。值必须不可变。
-
特殊情况,True和False在集合和字典可能会和0, 1 重复。hash函数对2者得到一样的值。如:
info = {0, 2, 3, 4, False, "国风", None, (1, 2, 3)} print(info) # {0, 2, 3, 4, "国风", None, (1, 2, 3)} info1 = { True:'alex', 1:'oldboy' } print(info1) # {True:'oldboy'}
3.11内存问题
-
变量
- 第一次赋值时,即创建它,之后赋值将会改变变量的值。
- 变量名本身是没有类型的,类型只存在对象中,变量只是引用了对象而已。
-
对象
- 对象是有类型的,例如各种数据类型。
- 对象是分配的一块内存空间,来表示它的值。
-
引用
在Python中从变量到对象的连接称作引用。
引用是一种关系,以内存中的指针的形式实现。-
简单引用
v1 = [11,22,33] #解释器创建了一块内存空间(地址),v1指向这里,v1引用此内存位置 v1 = [44,55,66] v1 = [1,2,3] # v1被多次赋值,即修改了v1的引用,把v1的指向关系变了,指向改为另一块内存地址。 v2 = [1,2,3] #解释器创建了另一块内存空间(地址),v2指向这里。 v1 = 666 # 同理,v1,v2指向不同的内存地址 v2 = 666 v1 = "asdf" # 特殊,对于赋值给字符串,v1,v2指向一个内存地址 (字符串不可变) v2 = "asdf" v1 = 1 v2 = 1 #特殊:v1,v2指向相同的内存地址 #解释:1. 整型: -5 ~ 256 ,py认为它是常用的,有缓存机制,就把v1和v2指向相同的内存地址,以节省内存。 ##### 2. 字符串:"alex",'asfasd asdf asdf d_asd'(字符串不可变 ),指向同一内存地址 ##### 3."f_*" * 3 - 重新开辟内存,一旦字符串*数字,数字不为1的运算,就重新开辟内存空间
-
共享引用
#示例一 a = 3 #解释器创建了一块内存空间(地址),a指向此处 b = a # b也指向次内存地址 #示例二(内部修改) v1 = [11,22,33] #解释器创建了一块内存空间(地址),v1指向此处 v2 = v1 #v2也指向这里,如果语句为:v2 = [11,22,33],则是解释器创建了另一块内存空间(地址),v2指向这里。只是v1和v2的值相同。 v1.append(123) #v1指向的内存地址添加上来元素666,v2跟着变更。 print(v2) # [11,22,33,123] #示例三(赋值) v1 = [11,22,33] v2 = [11,22,33] v1.append(123) print(v2) # [11,22,33] #示例四(重新赋值) v1 = [11,22,33] # v1指向一个内存地址 v2 = v1 # v2指向同一个内存地址 v1 = [44,55,66,77] #v1的指向关系改变,解释器创建了内存地址,并将v1的指向改为指向它。 print(v2) # v2的指向没有变化,输出[11,22,33]
-
== 和 is d的区别(重点)
-
== 用于比较值是否相等
-
is 用于比较内存地址是否相等/比较指向关系是否相同/比较指向的内存空间是否是同一个。
id(v1) # 返回得到 变量名v1指向的内存地址
-
小总结
- 变量是一个系统表的元素,拥有指向对象的连接的空间。
- 对象是分配的一块内存,有足够的空间去表示它们所代表的值。
- 引用是自动形成的从变量到对象的指针
-
-
3.12 深浅拷贝
-
简介
v = [1,2,3,[4,5,6],7,8,9] import copy v1 = copy.copy(v) #浅拷贝 v2 = copy.deepcopy(v) #深拷贝
-
对strintool类型而言,深浅拷贝没有区别.(不可变)
a = 'deng' #a指向内存中第一个内存地址 import copy b = copy.copy(a) #b指向内存中第一个内存地址 c= copy.deepcopy(a) #c指向内存中第一个内存地址 #注意:这里变量abc理应指向不同的内存地址,但因为小数据尺的缘故,内存地址相同.
-
list/dict/set类型来说,如果没有嵌套,深浅拷贝没有区别.(可变)
v = [1,2,3,[4,5,6],7,8,9] 有嵌套,有7个元素 v1 = [1,2,3,4,5,6,7,8,9] 没嵌套,有9个元素 import copy v2 = copy.copy(v1) v3 = copy.deepcopy(v1)
-
对嵌套的list/dict/set类型来说,深浅拷贝才有意义.
v = [1,2,3,[4,5,6],7,8,9] 有嵌套,有7个元素 import copy v1 = copy.copy(v) v2 = copy.deepcopy(v)
- 对于其中的元素都是不可变类型时,深拷贝和浅拷贝的结果都是一样的,都是只拷贝第一层
- 对于其中元素存在可变类型时,浅拷贝只拷贝第一层,深拷贝要拷贝所有的可变类型
-
特殊:tuple元组(不可变)
- 如果元组中不含有可变类型,同理字符串的深浅拷贝.
- 如果元组中含有可变类型,同理列表的深浅拷贝.
-
深拷贝和浅拷贝
- 浅拷贝:只拷贝第一层
- 深拷贝:拷贝嵌套层次中的所有可变类型
- 拷贝只针对可变类型:在内存中重新创建内存空间,对不可变数据类型无法操作.
-
可变数据类型和不可变数据类型
- 可变数据类型:在id不变的情况下,value可改变(列表/字典/集合是可变类型,但是字典中的key值必须是不可变类型)
- 不可变数据类型:value改变,id也跟着改变。(数字,字符串,布尔类型,都是不可变类型)
新人上路,请多多批评指正