Day 6-文件操作的其他方法 迭代器 生成器

1.读取时 可以使用 encoding='latin-1' 拉丁解码的方式尽可能的读取多的数据

(1)flush() 刷新

(2)tell() 光标所在位置 #除read()外 光标移动位置都是以字节为单位的

  一个字符三个字节

f = open('蔡晓武','r+',encoding='utf-8',newline='')

newline可以使 显示出来

(3)seek()移动光标 从0开始移动

  seek(10,1) 第二个参数表示光标的起始位置,0表示从头开始,1表示相对位置,相对于上一次,2表示从末尾开始取 f.seek(-5,2) 从末尾开始往回 每一行有一个

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()
原文地址:https://www.cnblogs.com/caixiaowu/p/12251388.html