python基础6-文件操作/迭代器/for循环/生成器
-
文件读操作
- windows的文件是以gbk存储的
- f = open('陈粒', ‘r’, encoding='utf-8'),以utf-8编码
- 在pycharm创建文件,在右下角选择编码方式,gbk
- 就是应用程序➡️通过操作系统➡️获得管理硬盘数据的渔网,就叫文件句柄
- 记得关闭文件
- f.read()读出来是str文件
- f.readable(),判断文件是否可读
- f.readline(),一次读一行
- f.readlines(),把文件读取成列表格式
-
文件写操作
- f.writelines(['555\n','666\n']),将列表按照一行一行写入文件f指的文件
- 写的东西都是字符串,不能是数字
- 用w和w+都是新建立一个文件,如已经有,则清空
-
文件追加操作append
- 文件没有修改一说,全都是覆盖,因为在硬盘上都是二进制存储。
- 从硬盘中读取文件,在内存中修改,然后覆盖到硬盘上
- with open('a.txt', 'w') as f: f.write('11111\n'),打开文件自动关闭
-
文件处理b模式
- rb的方式对linux没有任何用处,一切皆文件,linux全都是用二进制处理。但是windows不都是二进制,rb的b是bytes,字节方式
- 8个二进制bit是1个字节bytes。字节本质上就是二进制
- b的方式不能指定编码模式,f=open('test11.py', 'rb'),以二进制形式打开py文件,要想显示字符,还需解码,data.decode('utf-8')
- f=open('test22.py','wb'),f.write(bytes('111\n', encoding='utf-8')),以wb打开文件,写入时要将字符串通过bytes转换为二进制编码写入。或者直接x.encode('utf-8')
- b的方式,用来处理图片视频。二进制方法可以跨平台,跨系统
-
文件操作的其他方法
- f.closed,检测文件是否关闭
- f.encoding,获取文件打开的编码,不同平台对utf-8代号不同
- 文件1以utf-8编码,不能用其他编码读取,但可以用gbk等其他编码写入新东西
- 不清楚文件编码时,可以使用f=open('b.txt' , 'r' ,encoding='latin-1')万能编码。忽略
- f.flush(),把数据从内存刷新到硬盘上
- f.tell()读取文件中的光标位置
- f=open('b.txt','r',encoding='utf-8', newline=''),使用newline读取文件中真正的换行符号
- 只有f.read(3)是3个字符,即'a','b'为单位,其余的文件内光标移动都是以字节为单位,如f.seek,f.tell,f.truncate,f.readline
- ASCII码中,一个英文字母(不分大小写)为一个字节,一个中文汉字为两个字节
- UTF-8编码中,一个英文字母为一个字节,一个中文为三个字节。
- f.truncate(10)是一种文件的写操作,截取操作,将文件只保留从0-10个字节的内容
- f.seek()用来移动光标
-
文件seek方法补充
- seek(10,1),相对位置seek,前提是用rb打开文件,二进制执行
- seek(-10,2),从文件末尾开始seek,是倒叙
- 故障检查要查看最新的日志。
- 不用seek方法,data= f.readlines(),print(data[-1], decode('utf-8')),readlines读取文件每一行,然后打印最后一行
- 循环文件的推荐方式:for i in f: 一次一行,要一行给一行,而不是存储一个大列表。设置一个偏移量offs,seek(offs, 2),从末尾开始,每次一个offs
for i in f: offs = -10 while True: f.seek(offs,2) data = f.readlines() if len(data) >1: print('文件的最后一行是%s' %(data[-1].decode('utf-8'))) break offs*=2#如果不执行if,则加大偏移量,用于下次循环
- data是个列表,len(data)是指列表的行数
-
迭代器
- 迭代和递归的区别
- 递归,问路,是甲问乙,乙问丙,丙问丁,丁告诉丙,丙告诉乙,乙告诉甲
- 迭代,是甲问乙,乙让甲问丙,甲问丙,丙让甲问丁,甲问丁,得到结果
- 迭代器协议,对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个stoplteration异常,以终止迭代,即只能往下一步走,不能往后退。
- 可迭代对象,实现了迭代器协议的对象
- 字符串,列表,字典等for循环对象本身都不是可迭代对象,for循环先调用字符串/列表的_iter_方法,将其转换为可迭代对象,然后就有了next方法,最后捕捉异常
-
l = [1, 2, 3] iter_l=l.__iter__()#遵循迭代器协议,将列表生成可迭代对象 print(iter_l.__next__())
#for循环的机制跟索引没有一点关系,for循环就是基于迭代器协议工作的 - 基于索引和while只能遍历字符串/列表/元组等有下标的对象,for循环才能遍历字典/集合/文件对象。for循环处理字典时,迭代的是字典的key值,这是因为__iter__._next_就是key值
- print(next(iter_1)),next()是python内置函数,_iter_next_是数据对象内置的,next()本质就是在调用iter_l.next()方法
- 迭代器就是可迭代对象
-
生成器
-
可以理解为一种数据类型,自动实现了迭代器协议,不用iter方法,直接调用.__next__方法
- 函数中只要有yield,得到的就是生成器。yield相当于return,但是可以yield多次,可以保留函数运行状态,用next继续执行
- 三元表达式和列表解析
- 三元表达式,'SB' if name == 'alex' else '帅哥',如果if成立,返回SB,否则返回“帅哥”
- 列表解析,l=['鸡蛋%s' %i for i in range(10) ],生成['鸡蛋0','鸡蛋1'.....]的列表,中括号是列表解析式,小括号就是生成器表达式
- l1 = ['鸡蛋%s' %i for i in range () if i>5],这也是三元表达式,没有4元表达式
- 生成器表达式:laomuji = ('鸡蛋%s' %i for i in range(10)),laomuji也是生气器对象。
- sum,map,filter都是迭代器协议
- 生成器函数的好处,1不占空间,2效率高
- 生成器特性总结:
- 语法上和函数类似,都是使用def定义,生成器使用yield语句返回值
- 生成器可以被for循环
- 状态挂起,可以保存状态,延续上次操作
-
def get_population(): with open('人口普查', 'r', encoding='utf-8') as f: for i in f: yield i g = get_population() m = get_population()#用这种方式存储两个迭代器 all_pop = sum(eval(i)['population'] for i in g) print(all_pop) for k in m: print('%s %%' % ((eval(k)['population'] / all_pop) * 100))
-
生成者消费者模型
- 运行生成器的方式
- t.__next__()
- next(t)
- c1.send(‘abc’)从yield开始,把‘abc’赋值给yield,然后像__next__一样开始推动程序执行。
- yield 3相当于return,控制的是函数的返回值
- x= yield的另外一个特性,接受send传过来的值,赋值给x
- 使用send,在一个程序中实现并发操作
-
import time def consumer(name): print('我是[%s],我准备开始吃包子了' %name) while True: baozi=yield time.sleep(1) print('%s 很开心的把[%s]吃掉了'%(name, baozi)) def producer(): c1=consumer('wupeiqi') c2=consumer('yuanhao_sb') c1.__next__() c2.__next__() for i in range(10): time.sleep(1) c1.send('包子 %s' %i)#通过send调用consumer函数 c2.send('包子 %s' %i) producer()
- 异步携程