with与“上下文管理器”
相信很多人在阅读别人代码的时候,会看到用with打开文件的方式,如:
with open("code.py","w") as file:
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__() 方法。
class File(object):
def __init__(self,file_name,open_mode):
self.file = open(str(file_name),str(open_mode)) # 打开文件
def __enter__(self):
return self.file # 返回文件对象
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close() # 关闭文件
with File('code.py','w') as file:
print("-------writing-------")
file.write("life's short! Use python.")
在这里,我们可以看到with打开文件的原理代码,那么接下来给大家展示一下操作数据库的代码,当然,前提是你要准备好一个数据库(不重要的!)
from pymysql import *
class Database(object):
def __init__(self,name,password):
# 创建self.conn连接
self.conn = connect(host='localhost',port=3306,database=str(name),user='root',password=str(password),charset='utf8')
# 获得self.cursor对象
self.cursor = self.conn.cursor()
def __enter__(self):
return self.cursor # 返回self.cursor对象
def __exit__(self, exc_type, exc_val, exc_tb):
self.cursor.close() # 关闭self.cursor对象
self.conn.close() # 关闭self.conn连接
with Database('zzj_01','mysql') as db:
db.execute(""" select * from students; """) # 执行sql语句
content = db.fetchall() # 获取数据
# 遍历获取到的数据,打印每一条数据
for info in content:
print(info)
相信大家看到这里已经对with的用法已经很了解了,其实socket的with用法也差不多,大家可以自己动手敲一敲,自己好好体会一下。今天就到这里了,谢谢大家!