基础知识回顾——上下文管理器

上下文管理机制

很多情况,当我们使用完一个资源后,我们需要手动的关闭掉它,比如操作文件,建立数据库连接等。但是,在使用资源的过程中,如果遇到异常,很可能错误被直接抛出,导致来不及关闭资源。所以在大部分时候,我们使用”try-finally”语句来确保资源会关闭。

1 try:
2     f = open('test.txt', 'w+')
3     print(f.closed)        #判断文件是否关闭
4     f.write('Hello World!')
5 finally:
6     f.close()
7     print(f.closed)        #判断文件是否关闭

运行结果:

False
True    

Python语言里提供的with语句功能几乎同”try-finally”一样,代码更简洁。

1 with open("test.txt", "w") as f:
2     print(f.closed)
3     f.write("Hello World!")
4 print(f.closed)

运行结果:

False
True 

以上即是上下文管理器的用法,Python要求在with语句进入时自动调用__enter__()方法,其返回值会赋给as关键字后的变量;在with语句块退出后自动调用__exit__()方法。对于文件对象f来说,它定义了__enter__()和__exit__()方法(可以通过dir(f)看到)。在f的__exit__()方法中,有self.close()语句,这样就不用明文写f.close()了。

 

自定义上下文管理器

要自定义类似with语句的类,其内部必须提供两个内置方法__enter__以及__exit__。前者在主体代码执行前执行,后则在主体代码执行后执行。__enter__()返回的一对象作为as所指的变量。

 1 class ContextManagerDemo(object):
 2     def __init__(self,text):
 3         self.text = text
 4 
 5     def __enter__(self):
 6         self.text = "I say: " + self.text
 7         #print self     <__main__.ContextManagerDemo object at 0x023557D0>
 8         return self
 9 
10     def __exit__(self, exc_type, exc_val, exc_tb):  
11         self.text = self.text + "!"
12 #参数exc_type, exc_val, exc_tb分别代表异常类型,异常值,和异常的Traceback。当处理完异常后,可以让”__exit__()”方法返回True,此时该异常就不会再被抛出。正常程序中三个参数都是None
13 
14 with ContextManagerDemo('hello') as f:      #上下文管理器会使用__enter__()返回的这一对象作为as所指的变量f,如果没有返回对象,text属性则无法调用
15     print f.text
16 
17 print f.text

运行结果:

1 I say: hello
2 I say: hello!

 

上下文管理器应用

1.管理多个文件

1 with open('data.txt') as source, open('target.txt', 'w') as target:
2             target.write(source.read())

2.管理数据库游标

 1 import pymysql 
 2 
 3 def get_conn(**kwargs): 
 4   return pymysql.connect(host=kwargs.get('host', 'localhost'),
                 port=kwargs.get('port', 8080),
                 user=kwargs.get('user'),
                 passwd=kwargs.get('passwd')) 5 6 def main(): 7   conn = get_conn(user='Admin', passwd='123456') 8   with conn as cur: 9      cur.execute('show databases') 10     print cur.fetchall() 11 12 if __name__ == '__main__': 13   main()

 

posted on 2017-01-14 13:35  Ryana  阅读(216)  评论(0编辑  收藏  举报