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__() 方法。
- <span style="font-size:14px;">
- 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.")</span>
在这里,我们可以看到with打开文件的原理代码,那么接下来给大家展示一下操作数据库的代码,当然,前提是你要准备好一个数据库(不重要的!)
- <span style="font-size:14px;">
- 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)</span>
相信大家看到这里已经对with的用法已经很了解了,其实socket的with用法也差不多,大家可以自己动手敲一敲,自己好好体会一下。今天就到这里了,谢谢大家!