Day 6-文件操作的其他方法 迭代器 生成器
1.读取时 可以使用 encoding='latin-1' 拉丁解码的方式尽可能的读取多的数据
(1)flush() 刷新
(2)tell() 光标所在位置 #除read()外 光标移动位置都是以字节为单位的
一个字符三个字节
f = open('蔡晓武','r+',encoding='utf-8',newline='')
newline可以使\r \n显示出来
(3)seek()移动光标 从0开始移动
seek(10,1) 第二个参数表示光标的起始位置,0表示从头开始,1表示相对位置,相对于上一次,2表示从末尾开始取 f.seek(-5,2) 从末尾开始往回 每一行有一个\r \n
f = open('蔡晓武','rb') f.seek(10,1) print(f.tell()) f.seek(3,1) print(f.tell())
此时输出值为10 13
(4)read()读的是字符
(5)truncate()截取字符 参数可以指定要截取多少个字符
如何通过指针读取日志的最后一行
f = open('蔡晓武','rb') a = f.readlines() print(a[-1].decode('utf-8'))
读取文件每一行
f = open('蔡晓武','rb')for i in f: print(i.decode('utf-8'),end='')
循环文件的方式!!!
f = open('蔡晓武','rb') for i in f: print(i.decode('utf-8'),end='')
!!用seek()读取日志的最后一行
f = open('蔡晓武','rb') for i in f: offs = -3 while True: f.seek(offs,2) a = f.readlines() if len(a) >1: print('文件的最后一行%s' %a[-1].decode('utf-8')) break offs*=2
用offs是偏移量 用来承载 -3 一个字节
2.迭代器
1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代(只能往后走不能往前退)!!一切以迭代器生成的对象都是可迭代对象!!
2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个_iter_()方法)
3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum)
for循环可以遍历(字符串、列表、元组、字典、集合、文件对象)那这些都是可迭代对象?不是的,他们本身并没有遵循提供next方法,所以他们都不是可迭代对象。只不过在for循环内,调用了他们内部的_iter_方法,把他们变成了可迭代对象
a = 'hello' b = a.__iter__() print(b)
此时输出值为<str_iterator object at 0x0000020CBD870160> 成为了一个字符串迭代器
a = 'hello' b = a.__iter__() print(b.__next__()) print(b.__next__()) print(b.__next__())
此时b就变为了可迭代对象了,有了next()方法,输出值为 h e l
不用for循环,而用索引的方法去遍历
a='chris'
index = 0 while index<len(a): print(a[index]) index+=1
那为何要有for循环??while循环没法去遍历字典、集合、文件对象 因为这些都是无序的!!!
异常捕捉方法:
a = 'hello' b=a.__iter__() while True: try: print(b.__next__()) except StopIteration: print('迭代完毕了') break
此时输出值为
h
e
l
l
o
迭代完毕了
next()方法!! 原理为调用_iter_方法
3.生成器
(1)定义:可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(不用执行_iter_方法),所以生成器就是可迭代对象
(2)生成器分类及在Python中的表现形式:(Python有两种不同的方式提供生成器)
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回值
def test(): yield 1 yield 2 yield 3 yield 4 a = test() print(a) print(a.__next__())
此时输出值为
<generator object test at 0x00000255769AFD60>
1
第一个a打印下来的结果是生成器对象
def test(): for i in range(10): print('正在生产包子') yield '您的包子%s' %i a = test() b = a.__next__() print(b) c = a.__next__() print(c)
此时输出值为
正在生产包子
您的包子0
正在生产包子
您的包子1
2.生成器表达式:a = (i for i in range(10)) 比列表解析更加节省内存
生成器的好处:可以保留状态,每yield一次 ,指针就停留在yield执行完的位置
三元表达式:
name = 'chris' a = '帅哥' if name=='chris' else '丑男' print(a)
列表解析:
a = ['美女%s' %i for i in range(5) if i >3 ]
print(a)
此时输出值为['美女4']
sum()可以内部生成生成器
print(sum (i for i in range(101)))
此时输出值为5050 为1-100的和
人口普查题目:用生成器求出文件中的总人口
人口普查文件为:
{'地方':'北京','population':10000}
{'地方':'上海','population':30000}
{'地方':'山东','population':50000}
{'地方':'深圳','population':660000}
def get_population(): with open('人口普查','r+',encoding='utf-8') as f: for i in f: yield i get = get_population() sum_res = sum(eval(i)['population'] for i in get) print(sum_res)
此时就求出总人口750000
触发生成器继续向下进行的第三种方式: send(None)
def producer(): for i in range(100): d = yield '包子%s' %i print(d) c = producer() print(c.__next__()) c.send(None)
此时输出值为:
包子0
None
4.生产者消费者模型
import time def consumer(name): while True: baozi = yield time.sleep(1) print('%s吃了包子%s' %(name,baozi)) def producer(): a = consumer('蔡晓武') b = consumer('林子成') a.__next__() b.__next__() for i in range(10): time.sleep(1) a.send(i) b.send(i) producer()