阅读目录
一、引子
1 什么是数据?
x=10,10是我们要存储的数据
2 为何数据要分不同的类型
数据是用来表示状态的,不同的状态就应该用不同的类型的数据去表示
3 数据类型
数字(整形,长整形,浮点型,复数)
字符串
字节串:在介绍字符编码时介绍字节bytes类型
列表
元组
字典
集合
二、数字
整数与浮点数
#整型int 作用:年纪,等级,身份证号,qq号等整型数字相关 定义: age=10 #本质age=int(10) #浮点型float 作用:薪资,身高,体重,体质参数等浮点数相关 salary=3000.3 #本质salary=float(3000.3) #二进制,十进制,八进制,十六进制
#二:该类型总结 1 存一个值or存多个值 只能存一个值 2 无序 3 可变or不可变 !!!不可变:值变,id就变。不可变==可hash
其他数字类型(了解)
#长整形(了解) 在python2中(python3中没有长整形的概念): >>> num=2L >>> type(num) <type 'long'> #复数(了解) >>> x=1-2j >>> x.real 1.0 >>> x.imag -2.0
三、字符串
#作用:名字,性别,国籍,地址等描述信息 #定义:在单引号双引号三引号内,由一串字符组成 name='egon' #二:该类型总结 1 存一个值or存多个值 只能存一个值2 可变or不可变 !!!不可变:值变,id就变。不可变==可hash
优先掌握的操作:
#1、按索引取值(正向取+反向取) :只能取 msg='hello world' #第一位从0开始,最后一位是-1,倒数第二位是-2。 print(msg[0],msg[-1])) h d #2、切片(顾头不顾尾,步长) print(msg[0:3]) #>=0 <3 hel #不写代表从头开始,取到最后一位,如果写-1,最后一位取不到 print(msg[:]) hello world #设定步长为2,先取第一位,隔一位取一个;默认步长是1 print(msg[0:7:2]) hlow #反向取值,注意,顾头不顾尾,所以6能取到,而1不能 print(msg[6:1:-1]) w oll #将字符串反转 print(msg[-1::-1]) dlrow olleh #3、长度len print(len(msg)) #等同于,print(msg.__len__()),但是一般我们只用len() 11 #4、成员运算in和not in print('llo' in msg) True print('llo' not in msg) False #5、移除strip(两边开始,中间不管,默认可移除空格、 、 ) password=' alex 3714 ' print(password.strip()) alex 3714 #指定移除的字符 password='***alex3714***' print(password.strip('*')) alex3714 #从左边移除 password='***alex3714***' print(password.lstrip('*')) alex3714*** #从右边移除 print(password.rstrip('*')) ***alex3714 #与input连用 password=input('>>: ').strip() #6、切分split,默认按空格切分,切分结果存在列表中 user_info='root:x:0:0::/root:/bin/bash' res=user_info.split(':') print(res) ['root', 'x', '0', '0', '', '/root', '/bin/bash'] #指定从左向右,切割几次,默认切到结束 print(user_info.split(':',1)) ['root', 'x:0:0::/root:/bin/bash'] #从右向左,切割几次,注意列表顺序还是从左向右的。 print(user_info.rsplit(':',1)) ['root:x:0:0::/root', '/bin/bash'] #7、循环,把字符串每个字符遍历输出 msg='hel' for i in msg: print(i) h e l msg='hel' for i in range(len(msg)): #0 1 2 print(i,msg[i]) 0 h 1 e 2 l
#判断一个字符串是否为空 len('') == 0
字符串类型总结
#二:该类型总结 # 1 存一个值or存多个值 # 只能存一个值 # 2 有序 # 3 可变or不可变 # !!!不可变:值变,id就变。不可变==可hash
多变量赋值
# Assign values directly a, b = 0, 1 # Assign values from a list r,g,b = ["Red","Green","Blue"] # Assign values from a tuple x,y = (1,2)
#链式赋值 a=b=c=2 print(id(a),id(b),id(c)) 493143760 493143760 493143760 #交叉赋值 m=1 n=2 m,n=n,m print(m,n) #解压 l=[1,2,3,4] a,b,c,d=l print(a,b,c,d) 1 2 3 4 #用_作为占位符 l=[1,2,3,4] a,_,_,d=l print(a,d) #可以使用*_表示多个 a,*_,d=l print(a,d)
range
#renge(起始值,结束值,步长) #用于获取指定范围内的数。 #在2.7中,使用range会创建所有数字,占用内存。xrange是默认不创建,只在for循环中,一个循环创建一个;3中range就等同于xrange,xrange也移除了。 #默认从0开始,顾头不顾尾 for i in range(3): print(i) 0 1 2 #指定开始值开始 for i in range(1,3,1): print(i) 1 2 #反向取值 for i in range(3,1,-1) print(i) 3 2
#enumerate(列表或元祖,指定起始值) #enumerate自动生成一列从0开始自增1的数字,通过for循环与列表或者元祖的每个元素组成新的元祖。 li = ['电脑','鼠标','游艇','U盘'] for key in enumerate(li): print(key) (0, '电脑') (1, '鼠标') (2, '游艇') (3, 'U盘') #enumerate(li,1)生成从1开始自增1的数,注意虽然1对应电脑,但是取值的索引还是0。 li = ('电脑','鼠标','游艇','U盘') for x,y in enumerate(li,1): print(x,y) 1 电脑 2 鼠标 3 游艇 4 U盘
需要掌握的操作
#1、partition,rpartition #指定分割符,将字符串分割成三部分,保存到元祖中,只分割一次 msg='hello word' print(msg.partition('o')) ('hell', 'o', ' word') #从又向左找分隔符 msg='hello word' print(msg.rpartition('o')) ('hello w', 'o', 'rd') #2、lower,upper #将字符串大写 print('ALeX'.lower()) #将字符串小写 print('aaa'.upper()) #3、startswith,endswith #0开始5结束是否以'a'开始 msg='alex is SB' print(msg.startswith('a',0,5)) True #字符串是否以B结尾 print(msg.endswith('B')) #4、join #将元素都是字符串的列表或元祖的每个元素以指定字符串拼接(注意这是字符串的功能) li=['aa','bb','cc'] print('_'.join(li)) aa_bb_cc #如果元素中有数字,就会报错 #5、replace #将前面的内容替换成后面的内容,指定替换几次,默认全部替换 msg='alex say my name is alex ,alex have on tesla' print(msg.replace('alex','SB',1)) SB say my name is alex ,alex have on tesla #6、isdigit #isdigit:可以判断bytes和unicode类型,是最常用的用于于判断字符是否为"数字"的方法 age=input('>>: ') print(age.isdigit())
其他操作(了解即可)
#1、find,rfind,index,rindex,count #find找到字符串所在索引,不存在返回-1 msg='hello world' print(msg.find('wo')) #rfind反方向开始找 #index,rindex找索引,不存在报错 print(msg.index('SB')) #ValueError: substring not found #count,统计有多少个。 print(msg.count('l')) print(msg.count('l',0,5)) #指定范围 #2、center,ljust,rjust,zfill #center,居中,其余地方默认用空格填充 print('egon'.center(30,'*')) #ljust,左对齐 print('egon'.ljust(30,'*')) #rjust,右对齐 print('egon'.rjust(30,'*')) #zfill,居右,用0填充 00000000000000000000000000egon #3、expandtabs #指定 为几个字符 print('hello world'.expandtabs(10)) hello world #4、captalize,swapcase,title #captalize、将字符串首字母大写 print('i am egon'.capitalize()) I am egon #swapcase、大小写反转 print('AbC'.swapcase()) #title、将每个单词首字母大写 print('i am egon'.title()) #5、is数字系列(不能判断浮点数) num1=b'4' #bytes num2=u'4' #unicode,python3中无需加u就是unicode num3='壹' #中文数字 num4='Ⅳ' #罗马数字 isdigit()能识别:bytes,unicode的数字 isdecimal()能识别:unicode的数字 isnumeric()能识别:unicode,中文,罗马的数字 #6、is其他 # name='egon123' # print(name.isalnum()) #字符串由字母或数字组成 # print(name.isalpha()) #字符串只由字母组成 # print('abcA'.islower())#判断都是小写 # print(name.isupper())#判断都是大写 # print(' '.isspace())#判断是不是空格(不是空) # print('Am Ia'.istitle())#判断是不是标题 #判断字符串是否是合法的标识符,字符串仅包含中文字符合法 print('print1111'.isidentifier()) #实际上这#里判断的是变量名是否合法。如: '_a'.isidentifier() -->True '3a'.isidentifier() -->False '中国'.isidentifier() -->True
注意:所有修改字符串的操作都是新生成一个字符串,而不是修复源字符串,因为字符串是不可变的。
四、列表
#作用:多个装备,多个爱好,多门课程,多个女朋友等 #定义:[]内可以有多个任意类型的值,逗号分隔 my_girl_friends=['alex','wupeiqi','yuanhao',4,5] #本质my_girl_friends=list([...]) 或 l=list('abc')
优先掌握的操作:
1、按索引存取值(正向存取+反向存取):即可存也可以取
#取值与字符串操作一样 #对其中元素从新赋值,就是改变原列表 my_girl_friends=['alex','wupeiqi','yuanhao',4,5] print(my_girl_friends[1]) my_girl_friends[1]='bbb' print(my_girl_friends) wupeiqi ['alex', 'bbb', 'yuanhao', 4, 5]
2、切片(顾头不顾尾,步长)
#与列表操作一致 #ps:反向步长 l=[1,2,3,4,5,6] #正向步长 l[0:3:1] #[1, 2, 3] #反向步长 l[2::-1] #[3, 2, 1] #列表翻转 l[::-1] #[6, 5, 4, 3, 2, 1]
3、长度len(元素个数)
#实际上也是在调用__len__() print(my_girl_friends.__len__()) print(len(my_girl_friends))
4、成员运算in和not in
print('wupeiqi' in my_girl_friends) True
5、追加append
#列表不能通过定义新索引来追加,会报错 my_girl_friends=['alex','wupeiqi','yuanhao',4,5] my_girl_friends[5]=3 #IndexError: list assignment index out of range my_girl_friends.append(6) print(my_girl_friends) ['alex', 'wupeiqi', 'yuanhao', 4, 5, 6]
6、删除del、remove、pop
my_girl_friends=['alex','wupeiqi','yuanhao',4,5] #1、单纯的删除、不能把删除的值赋给其他变量 del my_girl_friends[0] print(my_girl_friends) ['wupeiqi', 'yuanhao', 4, 5] res=my_girl_friends.remove('yuanhao') print(my_girl_friends) print(res) ['alex', 'wupeiqi', 4, 5] None #2、删除并拿到结果:取走一个值,指定索引,不指定从最后一个开始 res=my_girl_friends.pop(2) print(my_girl_friends) print(res) ['alex', 'wupeiqi', 4, 5] yuanhao my_girl_friends=['alex','wupeiqi','yuanhao',4,5] print(my_girl_friends.pop(0)) #'alex' print(my_girl_friends.pop(0)) #'wupeqi' print(my_girl_friends.pop(0)) #'yuanhao'
7、循环
#每次循环得到一个元素 my_girl_friends=['alex','wupeiqi','yuanhao',4,5] for i in my_girl_friends: print(i)
要掌握的方法:
1、插入insert
my_girl_friends=['alex','wupeiqi','yuanhao','yuanhao',4,5] my_girl_friends.insert(1,'egon') print(my_girl_friends) ['alex', 'egon', 'wupeiqi', 'yuanhao', 'yuanhao', 4, 5]
2、清除clear
my_girl_friends=['alex','wupeiqi','yuanhao','yuanhao',4,5] my_girl_friends.clear() print(my_girl_friends) []
3、统计count
my_girl_friends=['alex','wupeiqi','yuanhao','yuanhao',4,5] print(my_girl_friends.count('yuanhao')) 2
4、拷贝copy
my_girl_friends=['alex','wupeiqi','yuanhao','yuanhao',4,5] l=my_girl_friends.copy() print(l) ['alex', 'wupeiqi', 'yuanhao', 'yuanhao', 4, 5]
5、扩展extend
#append和insert都只能加入一个值,extend的可以添加多个 #字符串、列表,元祖,字典等可for循环的,都可以被extend my_girl_friends=['alex','wupeiqi','yuanhao','yuanhao',4,5] l=['egon1','egon2'] my_girl_friends.extend(l) my_girl_friends.extend('hello')
6、取索引index
my_girl_friends=['alex','wupeiqi','yuanhao','yuanhao',4,5] print(my_girl_friends.index('wupeiqi')) print(my_girl_friends.index('wupeiqissssss')) #不存在报错ValueError: 'wupeiqissssss' is not in list
7、反转列表reverse
my_girl_friends=['alex','wupeiqi','yuanhao','yuanhao',4,5] my_girl_friends.reverse() print(my_girl_friends) [5, 4, 'yuanhao', 'yuanhao', 'wupeiqi', 'alex']
8、列表排序sort
#正向排序 l=[1,10,4,11,2] l.sort() print(l) [1, 2, 4, 10, 11] #反向排序 l.sort(reverse=True) print(l) [11, 10, 4, 2, 1] #注意: #字符串排序是从左向右一个一个比对,按照ascii的顺序比对 #列表只能是纯数字或者纯字符串才能排序,否则报错
#二:该类型总结 # 1 存一个值or存多个值 # 可以存多个值,值都可以是任意类型 # 2 有序 # 3 可变or不可变 # !!!可变:值变,id不变。可变==不可hash
注意:所有修改列表的操作都是直接操作源列表的。
五、元祖
#作用:存多个值,对比列表来说,元组不可变(是可以当做字典的key的),主要是用来读,如果元祖元素是列表或者字典,则列表或字典的元素是可以变的。 #定义:与列表类型比,只不过[]换成() age=(11,22,33,44,55)本质age=tuple((11,22,33,44,55)) #优先掌握的操作: #1、按索引取值(正向取+反向取):只能取 #2、切片(顾头不顾尾,步长) #3、长度 #4、成员运算in和not in #5、循环
#与列表都一样
需要掌握的内容
#1、查找索引 index age=(11,22,33,44,55) print(age.index(33)) print(age.index(33333)) #不存在报错 #2、统计count print(age.count(33))
#二:该类型总结 # 1 存一个值or存多个值 # 可以存多个值,值都可以是任意类型 # 2 有序 # 3 可变or不可变 # !!!不可变:值变,id就变。不可变==可hash
六、字典
#作用:存多个值,key-value存取,取值速度快 #定义:key必须是不可变类型,value可以是任意类型 info={'name':'egon','age':18,'sex':'male'} #本质info=dict({....}) 或 info=dict(name='egon',age=18,sex='male') 或 info=dict([['name','egon'],('age',18)]) 或 {}.fromkeys(('name','age','sex'),None) #除了元祖还可以是列表,字符串等可迭代的数据,然后每个键都赋值为None,可以批量创建键值对
#fromkeys()的定义: def fromkeys(*args, **kwargs): # 将所有key都赋予相同的值,第一参数为key,第二个参数为value,如果没有第二个参数则默认为none; #注意!!!是将所有key都赋予同一个值,比如如果value是一个[],则所有value指向的内存地址是同一个地址,也就是说往一个key的[]中append一个数据,则所有key的[]都被append了一个同样的数据,因为所有[]是同一个内存地址。 #如果想让value不一样, 可以这样: test = {} for i in range(10): test[i] = []
优先掌握的内容
#1、按key存取值:可存可取 可通过赋值一个不存在的key,来增加新的键值对。 d={'name':'egon'} print(d['name']) d['age']=18 print(d) #2、长度len,键值对个数 info={'name':'egon','age':18,'sex':'male'} print(len(info)) 3 #3、成员运算in和not in,针对key的,而不是值value info={'name':'egon','age':18,'sex':'male'} print('name' in info) True print('egon' in info) False #4、删除 #pop,移除指定键值对,并得到value info={'name':'egon','age':18,'sex':'male'} print(info.pop('name')) print(info) egon {'age': 18, 'sex': 'male'} #key不存在会报错,可指定不存在的key返回值而不报错。 print(info.pop('name111',None)) None #popitem,删除最后一个键值对(尽量当做无序的),得到键值对 info={'name':'egon','age':18,'sex':'male'} print(info.popitem()) ('sex', 'male') #5、键keys(),值values(),键值对items() #了解 print(info.keys()) #打印所有键 print(list(info.keys())[0]) #转换成列表取元素 print(list(info.values())) #打印所有值 print(list(info.items())) #打印所有键值对 #6、循环 #默认是对key进行循环 info={'name':'egon','age':18,'sex':'male'} for k in info: print(k,info[k]) for v in info.values(): print(v)
需要掌握的内容
#1、取值get info={'name':'egon','age':18,'sex':'male'} print(info['hobbies']) #取不存在的key报错退出 print(info.get('hobbies')) #使用get不会报错 None print(info.get('hobbies','没有')) #指定返回值 #2、update 、把一个字典加入另一个字典 info={'name':'egon','age':18,'sex':'male'} d={'x':1,'y':2,'name':'EGON'} info.update(d) print(info) {'name': 'EGON', 'age': 18, 'sex': 'male', 'x': 1, 'y': 2} #3、setdefault,如果key存在,则不修改,返回已经有的key对应的value info={'name':'egon','age':16,'sex':'male'} value=info.setdefault('age',18) print(value) print(info) 16 {'name': 'egon', 'age': 16, 'sex': 'male'} #如果key不存在,则新加一个键值对 info={'name':'egon','age':16,'sex':'male'} hobbies_list=info.setdefault('hobbies',[]) print(hobbies_list) hobbies_list.append('play') hobbies_list.append('read') print(info) [] {'name': 'egon', 'age': 16, 'sex': 'male', 'hobbies': ['play', 'read']}
#二:该类型总结 # 1 存一个值or存多个值 # 可以存多个值,值都可以是任意类型,key必须是不可变类型 # # 2 无序 # 3 可变or不可变 # !!!可变:值变,id不变。可变==不可hash
练习:
统计s='hello alex alex say hello sb sb'中每个单词的个数 结果如:{'hello': 2, 'alex': 2, 'say': 1, 'sb': 2}
#利用setdefault解决重复赋值 ''' setdefault的功能 1:key存在,则不赋值,key不存在则设置默认值 2:key存在,返回的是key对应的已有的值,key不存在,返回的则是要设置的默认值 d={} print(d.setdefault('a',1)) #返回1 d={'a':2222} print(d.setdefault('a',1)) #返回2222 ''' s='hello alex alex say hello sb sb' dic={} words=s.split() for word in words: #word='alex' dic.setdefault(word,s.count(word)) print(dic)
七、集合
#作用:去重,关系运算, #定义: 可变类型是不可hash类型 #定义集合: 集合:可以包含多个元素,用逗号分割, 集合的元素遵循三个原则: 1:每个元素必须是不可变类型(可hash,可作为字典的key) 2:没有重复的元素 3:无序 注意集合的目的是将不同的值存放到一起,不同的集合间用来做关系运算,无需纠结于集合中单个值
优先掌握内容
#优先掌握的操作: #1、定义集合:{}内用逗号分割每个元素都必须是不可变类型,元素不能重复,无序 s={1,2,3,1} #s=set({1,2,3,1}) #1、长度len print(len(s)) #2、成员运算in和not in names={'egon','alex'} print('egon' in names)
pythons={'egon','axx','ysb','wxx'} linuxs={'egon','oldboy','oldgirl','smallboy','smallgirl'} #3、|合集:老男孩所有的学生 print(pythons | linuxs) print(pythons.union(linuxs)) #4、&交集:同时报名两门课程的学生 print(pythons & linuxs) print(pythons.intersection(linuxs)) #5.1、-差集:只报名python课程的学生 print(pythons - linuxs) print(pythons.difference(linuxs)) #5.2、-差集:只报名linux课程的学生 print(linuxs-pythons) print(linuxs.difference(pythons)) #6、^对称差集:没有同时报名两门课程 print(pythons ^ linuxs) print(pythons.symmetric_difference(linuxs)) #7、== s1={1,2}
s2={1,2}
print(s1 == s2)
True
#8、父集:>,>= print(s1 >= s2) print(s1.issuperset(s2)) #9、子集:<,<= print(s2 <= s1) print(s2.issubset(s1))
#10、循环 linuxs={'egon','oldboy','oldgirl','smallboy','smallgirl'} for student in linuxs: print(student)
了解的知识点
#1、pop随机取走 s2={1,2,3,4,5,'a'} print(s2.pop()) print(s2) 1 {2, 3, 4, 5, 'a'} #2、add添加 s2={1,2,3,4,5,'a'} s2.add('b') print(s2) {1, 2, 3, 4, 5, 'a', 'b'} #3、删除 #discard删除不存在的元素不报错 s2={1,2,3,4,5,'a'} s2.discard('b') #remove删除不存在的元素报错 s2={1,2,3,4,5,'a'} s2.remove('b') #4、isdisjoint两个集合没有共同部分时,返回值为True s1={1,2,3,4,5,'a'} s2={'b','c',} print(s1.isdisjoint(s2)) True #5、把可迭代的数据转换成集合 # l=['a','b',1,'a','a'] # print(list(set(l))) # print(set('hello')) # print(set({'a':1,'b':2,'c':3})) #6、把差集从新赋值给集合 s1={1,2,3} s2={1,2,} print(s1-s2) print(s1.difference(s2)) s1.difference_update(s2) #s1=s1.difference(s2) print(s1) {3} {3} {3}
二.去重 1. 有列表l=['a','b',1,'a','a'],列表元素均为可hash类型,去重,得到新列表,且新列表无需保持列表原来的顺序 2.在上题的基础上,保存列表原来的顺序 3.去除文件中重复的行,肯定要保持文件内容的顺序不变 4.有如下列表,列表元素为不可hash类型,去重,得到新列表,且新列表一定要保持列表原来的顺序 l=[ {'name':'egon','age':18,'sex':'male'}, {'name':'alex','age':73,'sex':'male'}, {'name':'egon','age':20,'sex':'female'}, {'name':'egon','age':18,'sex':'male'}, {'name':'egon','age':18,'sex':'male'}, ]
#去重,无需保持原来的顺序 l=['a','b',1,'a','a'] print(set(l)) #去重,并保持原来的顺序 #方法一:不用集合 l=[1,'a','b',1,'a'] l1=[] for i in l: if i not in l1: l1.append(i) print(l1) #方法二:借助集合 l1=[] s=set() for i in l: if i not in s: s.add(i) l1.append(i) print(l1) #同上方法二,去除文件中重复的行 import os with open('db.txt','r',encoding='utf-8') as read_f, open('.db.txt.swap','w',encoding='utf-8') as write_f: s=set() for line in read_f: if line not in s: s.add(line) write_f.write(line) os.remove('db.txt') os.rename('.db.txt.swap','db.txt') #列表中元素为可变类型时,去重,并且保持原来顺序 l=[ {'name':'egon','age':18,'sex':'male'}, {'name':'alex','age':73,'sex':'male'}, {'name':'egon','age':20,'sex':'female'}, {'name':'egon','age':18,'sex':'male'}, {'name':'egon','age':18,'sex':'male'}, ] # print(set(l)) #报错:unhashable type: 'dict' s=set() l1=[] for item in l: val=(item['name'],item['age'],item['sex']) if val not in s: s.add(val) l1.append(item) print(l1) #定义函数,既可以针对可以hash类型又可以针对不可hash类型 def func(items,key=None): s=set() for item in items: val=item if key is None else key(item) if val not in s: s.add(val) yield item print(list(func(l,key=lambda dic:(dic['name'],dic['age'],dic['sex']))))
八、数据类型总结
按存储空间的占用分(从低到高)
数字 字符串 集合:无序,即无序存索引相关信息 元组:有序,需要存索引相关信息,不可变 列表:有序,需要存索引相关信息,可变,需要处理数据的增删改 字典:无序,需要存key与value映射的相关信息,可变,需要处理数据的增删改
按存值个数区分
标量/原子类型 | 数字,字符串 |
容器类型 | 列表,元组,字典 |
按可变不可变区分
可变 | 列表,字典 |
不可变 | 数字,字符串,元组 |
按访问顺序区分
直接访问 | 数字 |
顺序访问(序列类型) | 字符串,列表,元组 |
key值访问(映射类型) | 字典 |
九、运算符
详细:http://www.cnblogs.com/linhaifeng/articles/5935801.html#_label34
十、字符编码
1、存取文件不乱码的法则:用什么编码存的,就要用什么编码读 2、 unicode-----encode----->gbk (编码) gbk-------->decode----->unicode (解码) 3、 python3解释器默认使用的字符编码是utf-8 python2解释器默认使用的字符编码是ascii 内存中使用的是unicode 4 python2的str就是python3的bytes python2的unicode就是python3的str
详细:http://www.cnblogs.com/linhaifeng/articles/5950339.html
十一、文件处理
一、文件操作
1、操作文件的流程
#1. 打开文件,得到文件句柄并赋值给一个变量 f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r #2. 通过句柄对文件进行操作 data=f.read() #3. 关闭文件 f.close()
2、 f=open('a.txt','r')的过程分析
#1、由应用程序向操作系统发起系统调用open(...) #2、操作系统打开该文件,并返回一个文件句柄给应用程序 #3、应用程序将文件句柄赋值给变量f
注意!!!:
#强调第一点: 打开一个文件包含两部分资源:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为: 1、f.close() #回收操作系统级打开的文件 2、del f #回收应用程序级的变量 其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源, 而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close() 我们推荐傻瓜式操作方式:使用with关键字来帮我们管理上下文,不需要自己调用close with open('a.txt','w') as f: pass with open('a.txt','r') as read_f,open('b.txt','w') as write_f: data=read_f.read() write_f.write(data)
#强调第二点: f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。 这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。 f=open('a.txt','r',encoding='utf-8')
3、python2中的file与open
#首先在python3中操作文件只有一种选择,那就是open() #而在python2中则有两种方式:file()与open() 两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用file()来打开文件,相当于这是在构造文件类,而用open()打开文件,是用python的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如type(f) is file
二、打开文件的模式
文件句柄 = open('文件路径', '模式')
模式可以是以下方式以及他们之间的组合:
Character | Meaning |
‘r' | open for reading (default) |
‘w' | open for writing, truncating the file first |
‘a' | open for writing, appending to the end of the file if it exists |
‘b' | binary mode |
‘t' | text mode (default) |
‘+' | open a disk file for updating (reading and writing) |
‘U' | universal newline mode (for backwards compatibility; should not be used in new code) |
#1. 打开文件的模式有(默认为文本模式): r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】 w,只写模式【不可读;不存在则创建;存在则清空内容】 a, 之追加写模式【不可读;不存在则创建;存在则只追加内容;注意:a模式打开文件首先把光标移动到最后】 #2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式) rb wb ab 注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码 #3. 了解部分 "+" 表示可以同时读写某个文件 r+, 读写【可读,可写】 w+,写读【可读,可写】 a+, 写读【可读,可写】 x, 只写模式【不可读;不存在则创建,存在则报错】 x+ ,写读【可读,可写】 xb
三、操作文件的方法
a b c d #掌握 f.read() #读取所有内容,存放到字符串中,光标移动到文件末尾 a b c d f.readline() #读取一行内容,存放到字符串在,光标移动到第二行首部 a b f.readlines() #读取每一行内容,存放于列表中,注意有换行符 ['a b ', 'c d'] f.write('1111 222 ') #针对文本模式的写,需要自己写换行符,只能是单个字符串 f.write('1111 222 '.encode('utf-8')) #针对b模式的写,需要自己写换行符 f.writelines(['333 ','444 ']) #文件模式,可以把列表写入文件 f.writelines([bytes('333 ',encoding='utf-8'),'444 '.encode('utf-8')]) #b模式 #了解 f.readable() #文件是否可读 f.writable() #文件是否可读 f.closed #文件是否关闭 f.encoding #如果文件打开模式为b,则没有该属性 f.flush() #立刻将文件内容从内存刷到硬盘 f.name
四、文件内光标移动
一: read(3):
1. 文件打开方式为文本模式时,代表读取3个字符(只有这种模式时光标是以字符移动的)
with open('c.txt','rt',encoding='utf-8') as f: print(f.read(6)) print(f.tell())
2. 文件打开方式为b模式时,代表读取3个字节
with open('c.txt','rb') as f: print(f.read(6)) f.seek(2,1) print(f.tell()) print(f.read().decode('utf-8'))
二: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate
注意:
1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的
0模式:以文件最开始为参照,f.seek(6,0) 将光标从文件最开始向后移动6个字节
1模式:以当前位置为参照,f.seek(6,1) 将光标从当前位置向后移动6个字节;f.seek(-6,1)将光标从当前位置向前移动6个字节
2模式:以文件最末为参照,f.seek(0,2)将光标移动到文件最后;f.seek(-6,2)将光标从最后向前移动6个字节
2.tell获取当前文件读取指针的位置:print(f.tell())
3. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果
如果指定了可选参数 size,则表示截断文件为 size 个字节。 如果没有指定 size,则从当前位置起截断;截断之后 size 后面的所有字符被删除。
with open('access.log','a',encoding='utf-8') as f: f.truncate(3)
import time with open('test.txt','rb') as f: f.seek(0,2) while True: line=f.readline() if line: print(line.decode('utf-8')) else: time.sleep(0.2)
五、文件的修改
文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)
import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: data=read_f.read() #全部读入内存,如果文件很大,会很卡 data=data.replace('alex','SB') #在内存中完成修改 write_f.write(data) #一次性写入新文件 os.remove('a.txt') os.rename('.a.txt.swap','a.txt')
方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件
import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: for line in read_f: line=line.replace('alex','SB') write_f.write(line) os.remove('a.txt') os.rename('.a.txt.swap','a.txt')