十六、Python 上下文管理 Context Manager

要使用 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 os


class 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 sys
from StringIO import StringIO

oldstdout = sys.stdout
buf = StringIO()
sys.stdout = buf
print "hello"
print "world"
sys.stdout = oldstdout
print "Captured", repr(buf.getvalue())

class capture_output:
	def __init__(self):
		self.buf=StringIO()

	def __enter__(self):
		self.oldstdout=sys.stdout
		sys.stdout=self.buf
		return self.buf

	def __exit__(self,type,exc,traceback):
		sys.stdout=self.oldstdout

capture_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/practise
before with
__init__
__enter__
/private/tmp
__exit__
after with
/Users/macbook/Proj/practise
Captured 'hello\nworld\n'
hello
[Finished in 0.1s]



你可能感兴趣的:(python,Class)