標籤:python class
要使用 with 語句,首先要明白上下文管理器這一概念。有了上下文管理器,with 語句才能工作。下面是一組與上下文管理器和with 語句有關的概念。
上下文管理協議(Context Management Protocol):包含方法 __enter__() 和 __exit__(),支援該協議的對象要實現這兩個方法。
上下文管理器(Context Manager):支援上下文管理協議的對象,這種對象實現了__enter__() 和 __exit__() 方法。上下文管理器定義執行 with 語句時要建立的運行時上下文,負責執行 with 語句塊上下文中的進入與退出操作。通常使用 with 語句調用上下文管理器,
也可以通過直接調用其方法來使用。運行時上下文(runtime context):由上下文管理器建立,通過上下文管理器的 __enter__() 和
__exit__() 方法實現,__enter__() 方法在語句體執行之前進入運行時上下文,__exit__() 在語句體執行完後從運行時上下文退出。with 語句支援運行時上下文這一概念。上下文運算式(Context Expression):with 語句中跟在關鍵字 with 之後的運算式,該運算式要返回一個上下文管理器對象。
語句體(with-body):with 語句包裹起來的代碼塊,在執行語句體之前會調用上下文管
理器的 __enter__() 方法,執行完語句體之後會執行 __exit__() 方法。
#-----*-coding:utf-8-*-----"""Python’s with statement was first introduced five years ago, in Python 2.5. It’s handy when you have two related operations which you’d like to execute as a pair, with a block of code in between. The classic example is opening a file, manipulating the file, then closing it:with open('output.txt', 'w') as f: f.write('Hi there!')The above with statement will automatically close the file after the nested block of code. (Continue reading to see exactly how the close occurs.) The advantage of using a with statement is that it is guaranteed to close the file no matter how the nested block exits. If an exception occurs before the end of the block, it will close the file before the exception is caught by an outer exception handler. If the nested block were to contain a return statement, or a continue or break statement, the with statement would automatically close the file in those cases, too."""f = open("numbers.txt", "w")f.write("hello")f.close()with open("numbers.txt", "w") as f: f.write("hello")f = open("numbers.txt")print dir(f)import osclass chdir: def __init__(self, dir): self.dir = dir print "__init__" def __enter__(self): print "__enter__" self.olddir = os.getcwd() os.chdir(self.dir) return self def __exit__(self, *a): print "__exit__" os.chdir(self.olddir)print os.getcwd()print "before with"with chdir("/tmp") as x: print os.getcwd()print "after with"print os.getcwd()'''Problem Write a context manager capture_output to capture stdout inside a with block.with capture_output() as buf: print "hello"out = buf.getvalue()print "captured", repr(out)Hint: See StringIO.StringIO and sys.stdout.Lets try to understand how to capture output without context managers.'''import sysfrom StringIO import StringIOoldstdout = sys.stdoutbuf = StringIO()sys.stdout = bufprint "hello"print "world"sys.stdout = oldstdoutprint "Captured", repr(buf.getvalue())class capture_output:def __init__(self):self.buf=StringIO()def __enter__(self):self.oldstdout=sys.stdoutsys.stdout=self.bufreturn self.bufdef __exit__(self,type,exc,traceback):sys.stdout=self.oldstdoutcapture_output()print "hello"
result:
['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']/Users/macbook/Proj/practisebefore with__init____enter__/private/tmp__exit__after with/Users/macbook/Proj/practiseCaptured 'hello\nworld\n'hello[Finished in 0.1s]
十六、Python 上下文管理 Context Manager