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‘)

#貌似还有复杂写法,我得再看看

其实还是引用了很多现成的内容,暂时就是这么些了,很多需要复习哦

相关推荐