在Python中,您可以通过打开文件来访问文件。您可以使用open()函数来实现此目的。Open返回一个文件对象,其中包含用于获取有关打开的文件的信息和操作该文件的方法和属性。with语句使用“with”语句可以让代码简洁,异常处理也更加优雅。“with语句通过封装常用的准备和清理任务简化了异常处理。”此外,它会自动关闭文件。with语句提供了一种确保始终使用清理的方法。如果没有with语句,我们将编写以下内容:file=open("welcome.txt")data=file.read()print(data)file.close()#当你完成statementUsage'with'语句是一个新的控制流结构,它的基本结构是:"welcome.txt")asfile:#fileasareferencetothefileobjectdata=file.read()#usedatatodosomethingopenoutput.txtinwritemodewithopen('output.txt','w'复制代码)asfile:#outputtofilefile.write('Hithere!')请注意,我们不必编写file.close()。会被自动调用。原理'with'语句简化了以前使用try...finally块以确保执行清理代码的代码。在本节中,我将讨论常用语句。在下一节中,我将检查实现细节并展示如何编写用于该语句的对象。with后面的表达式需要支持上下文管理协议(即__enter__()和__exit__()方法)。withexpression[asvariable]:with-block在执行with-block之前调用了对象的__enter__()方法,因此设置代码可以运行。可以通过as将表达式的结果绑定到变量variable上(注意不是赋值给变量variable)。with块执行完成后,即使块引发异常,对象的__exit__()方法也会被调用,因此清理代码可以运行。要在Python2.5中启用该语句,您需要将以下指令添加到您的模块中:from__future__importwith_statement此语句将始终在Python2.6中启用。一些标准的Python对象现在支持上下文管理协议,并且可以与“with”语句一起使用。文件对象就是其中之一:withopen('/etc/passwd','r')asf:forlineinf:printline...more...执行完这条语句后,即使for循环是代码中如果block中途出现异常,f中的文件对象也会自动关闭。注意:在这种情况下,f是open()创建的同一个对象,因为file.__enter__()返回self。threading模块的锁和条件变量也支持'with'语句:lock=threading.Lock()withlock:#Criticalsectionofcode...这个锁在执行with块之前获取,总是在块完成后释放.decimal模块中新增的localcontext()函数可以方便地保存和恢复当前的decimalcontext,它封装了计算所需的精度和舍入特性:fromdecimalimportDecimal,Context,localcontext#显示默认精度:28位v=Decimal('578')printv.sqrt()withlocalcontext(Context(prec=16)):#此代码块中使用16位精度。#退出块后会恢复原来的上下文。print(v.sqrt())编写上下文管理器在幕后,with语句相当复杂。大多数人只会对现有对象使用“with”,不需要知道这些细节,如果你想编写自己的类来支持with语句,那么你需要了解上下文管理器。上下文管理协议的高级解释是:这个表达式将被评估并且应该产生一个叫做“上下文管理器”的对象。上下文管理器必须包含__enter__()和__exit__()方法。上下文管理器的__enter__()方法被调用。返回值分配给var。如果不存在asvar子句,则该值将被简单地丢弃。with块中的代码被执行。如果with块抛出异常,则使用sys.exc_info()返回的异常详细信息调用__exit__(type,value,traceback)。该方法的返回值控制是否重新引发异常:任何False值都会重新引发异常,True会抑制异常。通常很少需要抑制异常,因为如果这样做,包含“with”语句的代码的作者将永远不会意识到任何错误。如果with块没有抛出异常,__exit__()方法仍然会被调用,参数type、value和traceback都是None。让我们考虑一个例子。我不会提供详细的代码,而只是概述支持事务的数据库所需的方法。(对于那些不熟悉数据库术语的人:将对数据库的一组更改组合成一个事务。一个事务可以是提交的,这意味着所有的更改都写入数据库,或者回滚,这意味着所有的更改都被丢弃和删除。)database是不变的。请参阅任何数据库教科书以获取更多信息。)假设有一个表示数据库连接的对象。我们的目标是让用户编写如下代码:db_connection=DatabaseConnection()withdb_connectionascursor:cursor.execute('insertinto...')cursor.execute('deletefrom...')#...more操作...如果块中的代码运行完美,则应提交事务;如果有异常,事务应该被回滚。这就是我假设的DatabaseConnection的基本接口:classDatabaseConnection:...def__enter__(self):#Codetostartanewtransactioncursor=self.cursor()returncursor__enter__()方法很简单,只有开始新的交易。对于此应用程序,结果游标对象将是一个有用的结果,因此此方法将返回它。然后,用户可以将ascursor添加到他们的with语句中,以将游标绑定到变量名。classDatabaseConnection:#数据库接口defcursor(self):"返回一个游标对象并开始一个新的事务"defcommit(self):"提交当前事务"defrollback(self):"回滚当前事务"__exit__()方法有点复杂,方法必须检查是否发生异常。如果没有异常,则提交事务。如果出现异常,事务将被回滚。在下面的代码中,执行从函数的末尾开始,并返回默认值None。None为false,因此将自动重新引发异常。如果需要,可以更明确,并在标记的地方添加return语句。classDatabaseConnection:...def__exit__(self,type,value,tb):iftbisNone:#没有异常,所以提交self.commit()else:#异常发生,所以rollback.self.rollback()#返回Falsecontextlib模块contextlib模块提供了函数和装饰器,可用于编写与“with”语句一起使用的对象。装饰器称为contextmanager,它允许您编写一个生成器函数而不是定义一个新类。生成器应该只产生一个值。yield之前的代码将作为__enter__()方法执行,yield的值将是该方法的返回值,它将绑定到'with'语句的as子句中的变量(如果有).生成的代码将在__exit__()方法中执行。块内引发的任何异常都将由yield语句引发。上一节中的数据库示例可以使用以下装饰器编写:fromcontextlibimportcontextmanager@contextmanagerdefdb_transaction(connection):cursor=connection.cursor()try:yieldcursorexcept:connection.rollback()raiseelse:connection.commit()db=DatabaseConnection()withdb_transaction(db)ascursor:contextlib模块还将一些上下文管理器与嵌套(MGR1、MGR2、...)函数组合在一起,因此您无需编写嵌套的“with”语句。在此示例中,单个“with”语句启动数据库事务并获取线程锁:lock=threading.Lock()withnested(db_transaction(db),lock)as(cursor,locked):最后,Closing(object)function返回对象,以便它可以绑定到一个变量,并在块的末尾调用object.close()。importurllib,sysfromcontextlibimportclosingwithclosing(urllib.urlopen('http://bixuebihui.com'))asf:forlineinf:sys.stdout.write(line)参考:https://docs.python.组织/2.5/w...
