with语句的作用
先说说为什么会出现with,本来可以用try except finally来解决的问题,为什么要用with语句呢?
因为两个原因,其一,python是一门简短精悍的语言,提倡简洁的编码风格,也可以理解为pythonic。其二,with使用了上下文管理器,可以自动获取上下文相关内容,让开发者更专注于业务。
上下文管理器
前面提到了一个一个概念,上下文管理器,它是python中的一种协议,实现了这种协议的类的实例,都是上下文管理器对象。
那么怎么才能实现协议呢?
python中很简单,只需要在类定义的时候,实现两个方法即可。
一个是enter,另一个是exit。
下面我们来看一个示例:
class A():
def __init__(self, val_a):
self.a = val_a
def __enter__(self):
print("class A‘s __enter__ function.’")
def __exit__(self, exc_type, exc_val, exc_tb):
print("class A's __exit__ function.")
这样,就创建好了一个实现了上下文管理器协议的对象。你可以应用到任何类中。
Python中还有其他的高级特性也能创建上下文管理器,比如使用装饰器@contextmanager。
请看示例:
from contextlib import contextmanager
@contextmanager
def demo_func():
print("enter")
yield "demo_func"
print("exit")
with demo_func() as value:
print(value)
上面的代码使用了@contextmanager装饰器,contextmanager装饰被定义在contextlib模块中,所以需要先导入contextlib模块。
使用了@contextmanager装饰器修饰的方法都会变成上下文管理器对象。
上下文管理器先说这些,今天的重点是with语句。
with语句的语法
with expression as targer:
code body
expression是一个表达式,可以是一个函数,也可以是一个对象,但是如果是函数,函数必须返回一个实现了上下文管理器协议的对象,如果是一个对象,这个对象必须是上下文管理器对象。
target,是enter方法的返回值。
好了,目前知道这些就够了。
创建的with用法有哪些呢?
1. 操作文件
import os
with open('/usr/file.txt') as f:
for line in f:
print(line)
当操作文件时,with获取了应用上下文,在结束时会自动执行close函数来关闭文件。
2. 操作数据库
我们以Mysql为例,提示:这段代码使用pymysql模块,所以需要先安装,pip install pymysql即可。
如果总是没有反馈结果,可以翻墙,然后再次执行pip install pymysql命令就行了。
from pymysql import connect
class OpenDB():
def __init__(self, username, password, database):
self.conn = connect(host="localhost", port=3306, user=username, password=password, database=database, charset='utf-8')
self.cs = self.conn.cursor()
def __enter__(self):
return self.cs # 返回游标
def __exit__(self, exc_type, exc_val, exc_tb):
self.conn.commit() # 提交sql操作
self.cs.close() # 关闭游标
self.conn.close() # 关闭数据库连接
with OpenDB('root', '123456', 'test_database') as d:
sql = "select * from test_database"
d.execute(sql)
content = d.fetchall()
for temp in content:
print(temp)
首先导入pymysql模块中的connect对象,用来初始化数据库的连接。
然后程序创建了一个实现了上下文管理器协议的对象OpenDB,它有两个属性,一个保存了数据库的连接,另一个报错了数据库的游标,因为要通过游标来执行sql语句。
也许你会问,这个d是什么?
d是enter方法的返回值,嗯,很明显,这里的d是指向数据库游标的,所以才有了d.execute(sql)这一句执行sql的代码。
d.fetchall()用来匹配所有的查询结果。
最后用一个for in来遍历查询结果。
with还有很多场景都能用到
比如操作锁的时候,多线程中也会用到,暂时我还没有用过这些场景,未完待续吧。
网友评论