当前位置: 首页 > 后端技术 > Python

Python学习者文档读写指南(含基础和进阶,推荐合集)

时间:2023-03-25 20:37:20 Python

对于初学者来说,一份详尽清晰的指南非常重要。今天猫猫就和大家一起学习Python文件读写的内容。这部分内容是很常用的,掌握之后对工作和实战都有很大的帮助。学习是一个循序渐进的过程,欲速则不达。文章比较长,建议大家收藏一下。1.如何将列表数据写入文件?2.如何从文件中读取内容?3.各种需求的读写任务4.如何从with语句到contextmanager将列表数据写入文件?首先,我们看下面这段代码,思考一下:这段代码有没有问题,如果有,怎么改?li=['python','is','a','cat']withopen('test.txt','w')asf:f.write(li)现在公布答案,这段代码会报错误:TypeErrorTraceback(mostrecentcalllast)in()1withopen('test.txt','w')asf:---->2f.write(li)TypeError:write()argumentmustbestr,notlist上面代码的思路是将list列表的内容写入txt文件,但是报错TypeError:write()argumentmustbestr被报告。也就是说,write()方法必须接受一个字符串(str)类型的参数。Python有一个内置的str()方法,可以返回对象的字符串版本(Returnastringversionofobject)。所以,在上面的例子中,让我们尝试将f.write(li)更改为f.write(str(li)),首先进行字符串类型的转换。代码省略。这次没有报错,但是打开文件的时候我傻眼了。写的内容是“['python','is','a','cat']”。怎么能写成“python是猫”呢?还有一个用于文件写入操作的writelines()方法。它接收的参数是由字符串组成的序列。实际写出来的效果就是把所有的字符串拼接在一起。字符串本身也是一个序列,所以当参数为字符串时,writelines()方法等同于write()。#下面三种写法是等价的,都是写在字符串"pythonisacat"In[20]:withopen('test.txt','w')asf:...:f.writelines(['python','is','a','cat'])...:f.writelines('pythonisacat')...:f.write('pythonisacat')#下面2种写法是等价的,都是写到列表的字符串版本中"['python','is','a','cat']"In[21]:withopen('test.txt','w')asf:...:f.write(str(['python','is','a','cat']))...:f.writelines(str(['python','is','a','cat']))#作为反例,下面的写法都是错误的:In[22]:withopen('test.txt','w')作为f:...:f.writelines([2018,'is','a','cat'])#包含非字符串...:f.write(['python','is','a','cat'])#非字符串从上面可以看出,当列表中存在多个分散的字符串时,应该使用writelines()方法。如果字符串是一整段,那么直接使用write()方法即可。如果要以整个列表的形式写入文件,使用str()方法进行转换。这个问题还没有结束,如果列表中有元素不是字符串,需要把所有元素都取出来,怎么办?那么就不能直接使用write()和writelines()了,需要先用for循环,把每一个元素取出来,一个一个的str()。In[37]:content=[1,'is','everything']In[38]:withopen('test.txt','w')asf:...:foriincontent:...:f.write(str(i))需要注意的是writelines()不会自动换行。如果要实现列表元素之间的换行,一种方法是在每个元素后添加一个换行符“\n”。如果不想改变元素,最好使用for循环,写的时候在最后加上:foriincontent:f.writelines(str(i)+“\n”)。推而广之,经过实验,数字和原始类型也可以作为write()的参数而不需要转换。但是dict字典类型是不允许的,需要先用str()来处理。字典类型比较特殊。最好使用json.dump()方法写入文件。综上所述,write()接收的是字符串参数,适合一次性将所有内容写入一个文件;writelines()接收参数由strings组成的序列,适用于将列表的内容逐行写入文件。str()返回Python对象的字符串版本,请谨慎使用。如何从文件中读取内容?有几种方法可以从文件中读取内容:file.read([size])从文件中读取指定数量的字节,如果没有给定或为负,则读取全部。file.readline([size])读取整行,包括“\n”字符。file.readlines([sizeint])读取所有行并返回一个列表。如果给定sizeint>0,则设置一次读取多少字节,是为了减轻读取压力。总之,当不传参数时,read()对应write(),读取全部内容;readlines()对应于writelines(),它读取整个内容(包括换行符)并以列表的形式返回,每个换行符的内容作为列表的一个元素。In[47]:withopen('test.txt','r')asf:...:print(f.read())1iseverything.pythonisacat.thisistheend.In[48]:withopen('test.txt','r')asf:...:print(f.readlines())['1iseverything.\n','pythonisacat.\n','到此结束。']然而,上述两种方法都有一个缺点。当文件过大时,一次读取过多的内容会对内存造成很大的压力。读操作还有一个readline()方法,可以逐行读取。In[49]:withopen('test.txt','r')asf:...:print(f.readline())1iseverything.readline()读取第一行后返回,再次调用f.readline()将读取下一行。从这个角度来看,readline()太笨拙了。那么,有什么方法可以优雅的读取文件内容呢?回顾一下readlines()方法,它返回一个列表。是不是很奇怪,为什么好的内容要以列表的形式返回呢?再想想writelines()方法。将字符串列表写入文件正是这家伙所做的,而readlines()方法恰恰是它的逆操作!writelines()方法需要配合for循环,所以我们结合readlines()和for循环看看会发生什么。在[61]中:withopen('test.txt','r')asf:...:forlineinf.readlines():...:print(line)1iseverything.pythonisacat.到此结束。#读取的内容包含换行符,所以需要strip()去除换行符。在[62]:withopen('test.txt','r')asf:...:forlineinf.readlines():...:print(line.strip())1就是一切。python是猫,到此结束。综上所述,readline()比较鸡肋,用处不大;read()适用于读取内容较少的情况,或者需要一次处理所有内容的情况;而readlines()用得更多,也更灵活,因为for循环是一个迭代器,每次加载一部分内容,不仅减少内存压力,也方便逐行处理数据。各种需求的读写任务前两部分讲了读写文件的几个核心方法。它们工作的前提是需要先打开一个文件对象,因为读取或写入只能在文件操作符的基础上进行。手术。open()方法是用来打开文件的,所以我们继续讲这个方法。open()方法用于打开文件并返回文件对象。在处理文件的过程中需要这个函数。如果无法打开文件,将抛出OSError。open(file,mode='r',buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)open()方法的参数中的文件(file)为required,其他最常用的参数是模式(mode)和编码(encoding)。先说编码。一般来说,打开文件的编码方式以操作系统的默认编码为准。汉字可能会出现乱码,需要加上encoding='utf-8'。在[63]中:withopen('test.txt','r')asf:...:forlineinf.readlines():...:print(line.strip())----------------------UnicodeDecodeErrorTraceback(最近调用最后)in()1withopen('test.txt','r')asf:---->2forlineinf.readlines():3print(line.strip())UnicodeDecodeError:'gbk'codeccan'tdecodebyte0xa4inposition26:illegal多字节序列[65]:withopen('test.txt','r',encoding='utf-8')asf:...:forlineinf.readlines():...:print(line.strip())wxpublicznumberpython编程学习圈python是一只猫。除了模式之外,它还指定文件打开的模式。'r':以只读模式打开(默认模式,文件必须存在)'w':以只写模式打开。如果文件存在,则清空文件并重新创建;如果不存在,则创建一个新的“a”:以追加模式打开。如果文件存在,则追加到文件末尾;如果该文件不存在,将创建一个新的引用。常用模式组合'r'或'rt':默认模式,文本读取模式'w'或'wt':以文本模式写入打开(打开前文件清空)'rb':以二进制读取模式打开'ab':openinbinaryappendmode'wb':openinbinarywritemode(fileisemptybeforeopen)'r+':readintext以写模式打开,默认写指针从文件的开头开始,所以文件将是overwritten'w+':以文本读写方式打开(文件打开前清空)'a+':以文本读写方式打开(只写入文件末尾)'rb+':以二进制方式打开/writemode'wb+':openinbinaryread/writemode(openedbeforecleared)'ab+':openinbinaryread/writemode乍一看,模式有很多种,然而,它们只是相互结合。建议记住最基本的w、r、a,遇到特殊场景再看一遍即可。从with语句到上下文管理器的基础部分,下面是进阶部分。要知道它,还要知道为什么。1、with语句是初学者的常识。首先解释一下为什么上一篇文章中直接使用with语句。with语句是读写文件时一种优雅的写法,对于Python初学者来说已经是默认常识了。如果你还不知道,先看看使用和不使用with语句的比较:#不使用with语句的正确写法try:f=open('test.txt','w')f.writelines(['python','is','a','cat'])finally:iff:f.close()#with语句的正确写法withopen('test.txt','w')asf:f.writelines(['python','is','a','cat'])因为文件对象会占用操作系统的资源,操作系统可以打开的文件数同时是有限的,所以open()方法必须在close()方法之后调用。另外,读写操作可能会出现IO异常,所以要加上try...finally,保证无论如何都会调用close()方法。这样写虽然万无一失,但是实在是太麻烦了,一不小心就可能漏掉或者出错。with语句会保证调用close(),只需要一行代码,简直不要太优雅!因此,with语句是Python初学者的必备技能。2.什么是上下文管理器?接下来,重头戏来了,什么是上下文管理器(contextmanager)?上下文管理器就是这样一个对象:它定义了程序运行时需要建立的上下文,处理程序的进入和退出,实现了上下文管理协议,即__enter__()和__exit__()方法在对象中定义。__enter__():进入运行时上下文,返回运行时上下文相关的对象。with语句会将此返回值绑定到目标对象。__exit__(exception_type,exception_value,traceback):退出运行时上下文,定义上下文管理器在块执行(或终止)后应该做什么。它可以处理异常,清理场景,或者处理with块中的语句执行完成后需要处理的动作。注意enter和exit前后有两条下划线。Python中有很多类似的方法。他们非常神秘和强大。江湖人常称其为“黑魔法”。例如,迭代器协议实现了__iter__方法。在Python的内置类型中,有很多类型支持上下文管理协议,比如file、thread.LockType、th??reading.Lock等。上下文管理器不能单独使用,必须与with结合使用,with语句可以在代码块运行前进入运行时上下文(执行_enter_方法),代码块结束后退出上下文(执行__exit__方法)。with语句适用于访问资源,保证无论在使用过程中是否发生异常,都进行必要的“清理”操作,释放资源,例如使用后自动关闭文件,自动获取和释放线程中的锁,等3.自定义上下文管理器除了Python的内置类型外,任何人都可以定义自己的上下文管理器。下面是一个例子:)self.f.write("enternow\n")returnself.f#作为as说明符指定的变量的值def__exit__(self,type,value,tb):self.f.write("exitnow")self.f.close()returnFalse#异常将通过OpenFile('test.txt','w')asf:f.write('HelloWorld!\n')最终写入文件结果是:enternowHelloWorld!exitnow上下文管理器必须为__enter__()和_exit_()方法提供定义,缺少任何一个都将导致AttributeError。contextmanager在执行过程中可能会出现异常,_exit_()的返回值将决定异常处理方式:如果返回值等于False,则将异常重新抛给上层;如果返回值等于True,则异常将被忽略,继续执行下面的代码。__exit()__有三个参数(exception_type、exception_value、traceback),分别是异常的相关信息。4.contextlib实现上下文管理器在上面的例子中,自定义上下文管理器的写法比较繁琐,而且只能在类级别使用。为了更好的辅助上下文管理,Python提供了一个内置的contextlib模块,可以很容易的实现一个函数级的上下文管理器。该模块本质上是通过装饰器和生成器来实现上下文管理器,可以直接作用于函数/对象,而不必关心enter__()和__exit()方法的具体实现。先修改上面的例子,然后我们会相应地解释:fromcontextlibimportcontextmanager@contextmanagerdefopen_file(name):ff=open(name,'w')ff.write("enternow\n")try:yieldffexceptRuntimeError:passff.write("exitnow")ff.close()withopen_file('test.txt')asf:f.write('HelloWorld!\n')contextmanager是要使用的装饰器,yield关键字将普通函数变成生成器。yield的返回值(ff)等于上例中__enter__()的返回值,即as语句的值(f),yield前后的内容就是_enter_()和_exit_()方法。使用contextlib,类定义,可以避免_enter_()和__exit()__方法,但是我们需要捕获可能的异常(比如yield只能返回一个值,否则会引发异常RuntimeError),所以try...except语句不能忽略。以上就是本次分享的全部内容。想了解更多python知识,请前往公众号:Python编程学习圈,发“J”免费领取,每日干货分享