Python中的with“上下文管理器”

with与“上下文管理器”

    关于with打开文件的方式。如:


[python]  view plain  copy
  1. with open("code.py","w") as file:  
  2.   
  3.     file.write("Life's short! Use python.")  

    那么这种打开方式有什么好处呢?

    对于文件而言,如果需要频繁地操作的话,没完没了的关闭确实不胜其烦,有的时候比如 Python 程序打开一个文件,往文件中写内容,写完之后,就要关闭该文件,否则会出现什么情况呢?极端情况下会出现 "Too many open files" 的错误,因为系统允许你打开的最大文件数量是有限的。同样,对于数据库,如果连接数过多而没有及时关闭的话,就可能会出现 "Can not connect to MySQL server Too many connections",因为数据库连接是一种非常昂贵的资源,不可能无限制的被创建。于是乎,一种新的打开文件的方式诞生了——也就是with。

    with的好处显而易见,就是在打开文件,并且操作之后,python程序会自动地为你关闭这个文件,而不再需要手动地去关闭,这就防止了同时有很多文件打开的情况,也就避免了一些不必要的错误。那么,既然with这么好用,那它的底层原理到底是什么呢?我们可不可以用with来进行其他的类似数据库,socket连接等的响应操作呢?

    with的底层原理是使用了上下文管理器:

    任何实现了 __enter__() 和 __exit__() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。显然,文件(file)对象也实现了上下文管理器。__enter__() 和 __exit__() 方法都是属于魔法方法,相信大家对魔法方法都已经耳熟能详了。通俗来说,就是在特定的情况下,魔法方法会自动执行。在这里,__enter__() 方法会在打开文件的时候执行,并且返回资源对象,这里就是你将要打开的那个文件对象,__exit__() 方法则会在操作完文件之后执行,这里会处理一些清除工作那么文件对象是如何实现这两个方法的呢?我们可以模拟实现一个自己的文件类,让该类实现 __enter__() 和 __exit__() 方法。

[html]  view plain  copy
  1.   
[html]  view plain  copy
  1. <span style="font-size:14px;">  
  2.   
  3. class File(object):  
  4.     def __init__(self,file_name,open_mode):  
  5.         self.file = open(str(file_name),str(open_mode))      # 打开文件  
  6.   
  7.   
  8.     def __enter__(self):  
  9.         return self.file        # 返回文件对象  
  10.   
  11.   
  12.     def __exit__(self, exc_type, exc_val, exc_tb):  
  13.         self.file.close()       # 关闭文件  
  14.   
  15.   
  16.   
  17.   
  18. with File('code.py','w') as file:  
  19.     print("-------writing-------")  
  20.     file.write("life's short! Use python.")</span>  

在这里,我们可以看到with打开文件的原理代码,那么接下来给大家展示一下操作数据库的代码,当然,前提是你要准备好一个数据库(不重要的!)

[python]  view plain  copy
  1.   
[python]  view plain  copy
  1. <span style="font-size:14px;">  
  2.   
  3. from pymysql import *  
  4.   
  5.   
  6.   
  7.   
  8. class Database(object):  
  9.     def __init__(self,name,password):  
  10.         # 创建self.conn连接  
  11.         self.conn = connect(host='localhost',port=3306,database=str(name),user='root',password=str(password),charset='utf8')  
  12.         # 获得self.cursor对象  
  13.         self.cursor = self.conn.cursor()  
  14.   
  15.   
  16.     def __enter__(self):  
  17.         return self.cursor      # 返回self.cursor对象  
  18.   
  19.   
  20.     def __exit__(self, exc_type, exc_val, exc_tb):  
  21.         self.cursor.close()     # 关闭self.cursor对象  
  22.         self.conn.close()       # 关闭self.conn连接  
  23.   
  24.   
  25.   
  26.   
  27. with Database('zzj_01','mysql') as db:  
  28.     db.execute(""" select * from students; """)     # 执行sql语句  
  29.     content = db.fetchall()                         # 获取数据  
  30. # 遍历获取到的数据,打印每一条数据  
  31. for info in content:  
  32.     print(info)</span>  

相信大家看到这里已经对with的用法已经很了解了,其实socket的with用法也差不多,大家可以自己动手敲一敲,自己好好体会一下。今天就到这里了,谢谢大家!
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值