Python之旅的第3²+1天(文件操作、迭代器、生成器)
今天计划看的一个关于昨天内容的博客最终还是没看,躺下的感觉总是那么爽,爽到你不想起床,但是早晨是例外的,因为精神可以控制肉体。
首先是关于文件操作的补充:
# 以字节形式读取文件: # f = open('test.txt','rb') #注意:如果以字节形式读取文件,此时是不能设置encoding = # f.close() # 关于换行,当你以readlines读取文件的时候会获得\r\n,但是Python会自动帮你转换为\n # 通过在打开文件后面设置上newline # f = open('test','r',encoding = 'utf-8') # print(f.readlines()) #输出结果:['第二行前面皮一下\n', 'oujielun\n', 'kobe\n', '第二行前面皮一下\n'] # f.close() # # f = open('test','r+',encoding = 'utf-8',newline = '') # print(f.readlines()) #输出结果:['第二行前面皮一下\r\n', 'oujielun\r\n', 'kobe\r\n', '第二行前面皮一下\r\n'] # f.close() #在open打开文件的时候设置newline默认参数为空后,Python就不会再自动将\r\n转换为\n #但是在使用seek方法的时候,计算字节数时,在Windows中依旧按照\r\n各自计算一个字节,即换行为两个字节 #字节形式文件写入方法 # f = open('test_1.txt','wb') #字节形式写入不能设置encoding哦 # f.write(bytes('你好啊',encoding = 'utf-8')) #这里在使用bytes方法输出‘你好啊’对应字节码时是需要注明参考编码表的 # f.close() #字节形式读取文件的方式 # f = open('test_1.txt','rb') #同理,字节形式读取也是不能在打开文件的时候设置encoding # data = f.read() # print(data) #输出结果:b'\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a'('你好啊'的字节形式) # print(data.decode('utf-8')) #输出结果:你好啊 # f.close() #为什么会存在用字节形式读取文件的这种反人类操纵呢? #我们处理的文件可不仅仅是字符串的形式哦,还有很多照片、视频等文件 #字节形式可以匹配一切设备,赞。 #文件操作的其他方法 #closed 检查文件是否关闭,有时候还是会忘记写f.close() #f.encoding 显示文件打开所参考的编码(和文件存贮的编码形式无关哦) #f.flust 刷新文件,相当于实现文件写入时定期的自动保存功能 #f.name 获取文件名称(目前感觉好傻逼的方法啊) #f.tell 显示当前光标读取的所在位置(以字节形式反馈) # f = open('test','r+',encoding = 'utf-8') # print(f.readline()) #输出结果:'第二行前面皮一下',8个字用utf-8是24个字节,同时加上\r\n各占一个字节 # print(f.tell()) #输出结果为:26 3*8+2 # print(f.closed) #输出Flase # f.close() #在文件中的所有读取方法中,只有read是按照字符数的个数进行移动光标, # /其他所有方法都是按照字节进行移动光标 # f.seek 非常重要的一个方法,光标的移动 # 书写的格式为f.seek(a,b) #按照字节数移动光标 # a表示光标移动的距离,b表示光标移动的方向 # 不输入参数b:默认为0,表示从文件最开始的位置移动a个字节 # b = 1 :表示从光标当前所在位置向后移动a个字节 # b = 2 :表示光标从文件最后向前移动a个字节,此时的a必须是一个负数 # seek的b值为默认的0时 # f = open('test','r',encoding = 'utf-8') #test文件内容 # ['第二行前面皮一下\n', 'oujielun\n', 'kobe\n', '第二行前面皮一下\n'] # print(f.readline()) #输出结果:第二行前面皮一下 # f.seek(6) #从文件开始向后移动6个字节 # print(f.readline()) #此时输出的内容:行前面皮一下 # f.close() # seek的b值等于1时,移动光标的相对位置 # ['第二行前面皮一下\n', 'oujielun\n', 'kobe\n', '第二行前面皮一下\n'] # f = open('test','rb') #test文件内容,忘记了一个很重要的东西,要以字节的方式进行处理 # f.seek(6,1) #从文件开始向后移动6个字节 # print((f.readline()).decode('utf-8')) #此时输出的内容:行前面皮一下 # f.seek(6,1) #上一句的readline已经把光标移动到第二行的开端,现在从第二行开始向后移动6位 # print((f.readline()).decode('utf-8')) #此时输出的内容:'un',此时是第二行开始向后移动了6个字节 # f.close() # b = 2 时的操作,记住此时的a一定是负数 # f = open('test','rb') #test文件内容 # # ['第二行前面皮一下\n', 'oujielun\n', 'kobe\n', '第二行前面皮一下\n'] # f.seek(-6,2) #从最后向前移动6个字节 # print((f.readline()).decode('utf-8')) #此时输出的内容:'一下' # f.close() # seek的b值等于2时,是文件操作中唯一从后向前读取文件的方法 # 可用于读取大规模文件的最后一行,比如大型网站的管理日志 # f=open('test_1.txt','rb') # # for i in f: # offs=-3 # n=0 # while True: # f.seek(offs,2) # data=f.readlines() # if len(data) > 1: # print('最后一行',data[-1].decode('utf-8')) # break # offs*=2 # 加入没有seek方法,我们读取最后一行文件的方法 # f = open('test_1.txt','rb') # data = f.readlines() #这个创建list的过程会占用大量内存空间 # print('最后一行',data[-1].decode('utf-8'))
关于迭代器:
迭代器的概念:
#迭代器即迭代的工具,那什么是迭代呢? #迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 while True: #只是单纯地重复,因而不是迭代 print('===>') l=[1,2,3] count=0 while count < len(l): #迭代 print(l[count]) count+=1
为何要有迭代器?什么是可迭代对象?什么是迭代器对象?
#1、为何要有迭代器? 对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器 #2、什么是可迭代对象? 可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下 'hello'.__iter__ (1,2,3).__iter__ [1,2,3].__iter__ {'a':1}.__iter__ {'a','b'}.__iter__ open('a.txt').__iter__ #3、什么是迭代器对象? 可迭代对象执行obj.__iter__()得到的结果就是迭代器对象 而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象 文件类型是迭代器对象 open('a.txt').__iter__() open('a.txt').__next__() #4、注意: 迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
迭代器对象的使用
dic={'a':1,'b':2,'c':3} iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身 iter_dic.__iter__() is iter_dic #True print(iter_dic.__next__()) #等同于next(iter_dic) print(iter_dic.__next__()) #等同于next(iter_dic) print(iter_dic.__next__()) #等同于next(iter_dic) # print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志 #有了迭代器,我们就可以不依赖索引迭代取值了 iter_dic=dic.__iter__() while 1: try: k=next(iter_dic) print(dic[k]) except StopIteration: break #这么写太丑陋了,需要我们自己捕捉异常,控制next,python这么牛逼,能不能帮我解决呢?能,请看for循环
for循环
#基于for循环,我们可以完全不再依赖索引去取值了 dic={'a':1,'b':2,'c':3} for k in dic: print(dic[k]) #for循环的工作原理 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
迭代器的优缺点
#优点: - 提供一种统一的、不依赖于索引的迭代方式 - 惰性计算,节省内存 #缺点: - 无法获取长度(只有在next完毕才知道到底有几个值) - 一次性的,只能往后走,不能往前退
关于生成器:
什么是生成器
#只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码 def func(): print('====>first') yield 1 print('====>second') yield 2 print('====>third') yield 3 print('====>end') g=func() print(g) #<generator object func at 0x0000000002184360>
生成器就是迭代器
g.__iter__ g.__next__ #2、所以生成器就是迭代器,因此可以这么取值 res=next(g) print(res)
三元表达式
#三元表达式 name = input('>>>') if name == 'alex': print('sb') else: print('shuaige') #以上if段落可简写为 print('sb') if name == 'alex' else print('shuaige') #貌似还有复杂写法,我得再看看
其实还是引用了很多现成的内容,暂时就是这么些了,很多需要复习哦