Python面试专题--with关键字与上下文管理

Python面试专题--with关键字与上下文管理_第1张图片


作者 | zone7

来源 | zone7(ID:zone7py


目录

  • 瞎比比

  • 聊聊为什么要用 with、contextlib

  • 举个栗子

  • with、contextlib 原理

  • 常见的 with 用例


瞎比比


本文源码地址:

 
   

最近秋招就要到了,我准备了 Python 面试的一系列专题,涉及到 Python 的一些高级用法,例如:垃圾回收机制、装饰器、上下文管理器等等。希望在秋招路上助你一臂之力。


聊聊为什么要用 with、contextlib


通常情况下,我们在做一些资源操作的时候,都要做 open 和 close 等相关的操作,为的就是使用完资源之后,及时清理不用的资源,避免占用内存。例如,典型的数据库操作:

conn = pymysql.connect()	
cur = conn.cursor()	
sql = "INSERT INTO `users` (`name`, `password`, `age`, `sex`) VALUES (%s, %s, %s, %s)"	
cur.execute(sql)	
conn.commit()	
cur.close()	
conn.close()

如果我们经常操作一些资源,那是不是就得经常做一些重复的操作?甚至有时候,我们忘记进行资源回收操作,导致内存泄露,或许可能会导致线上事故。那我们有什么操作能够处理这些麻烦,或者说有什么一劳永逸的方法吗?答案是有的,正是此文的标题,且往下看。


举个栗子


我先来举个栗子吧,看看这个 with、contextlib 究竟是怎么方便的,且看下面的代码。建议你在看完 with、contextlib 原理之后,再一次回看这些栗子,你会有收获的。

class MysqlDb():	
    def __init__(self, database, host="localhost", user="root", prot=3306, password="root", charset="utf8mb4"):	
        self.conn = pymysql.connect(host=host, user=user, password=password, port=prot, database=database,	
                                    cursorclass=pymysql.cursors.DictCursor, charset=charset)	
        self.cur = self.conn.cursor()	

	
    def __enter__(self):	
        return self.cur	

	
    def __exit__(self, exc_type, exc_val, exc_tb):	
        self.conn.commit()	
        self.cur.close()	
        self.conn.close()	

	

	
with MysqlDb(database="test", ) as db:	
    sql = "select * from users"	
    db.execute(sql)	
    print(db.fetchone())	
    intert_sql = "INSERT INTO `users` (`name`, `password`, `age`, `sex`) VALUES (%s, %s, %s, %s)"	
    db.execute(intert_sql, ('zone7', 'pwd', "18", "man"))	

	

	
@contextlib.contextmanager	
def get_mysql_cur(database, host="localhost", user="root", prot=3306, password="root", charset="utf8mb4"):	
    conn = pymysql.connect(host=host, user=user, password=password, port=prot, database=database,	
                           cursorclass=pymysql.cursors.DictCursor, charset=charset)	
    cur = conn.cursor()	
    yield cur	
    conn.commit()	
    cur.close()	
    conn.close()	

	

	
with get_mysql_cur(database="test", ) as db:	
    sql = "select * from users"	
    db.execute(sql)	
    print(db.fetchone())

结果:

{'age': '18', 'name': 'zone', 'sex': 'man', 'id': 1, 'password':	
'123'}

with、contextlib 原理

在看完栗子之后,是不是觉得很方便?建议自行跑一下代码,将 host、账号、密码等必要信息修改成自己的。需要说明下的是,这个应用还是比较广泛的,不是仅仅局限于数据库中的应用。那么接下来我们就来说说其中的原理。

class MysqlDb():	
    def __init__(self, database, host="localhost", user="root", prot=3306, password="root", charset="utf8mb4"):	
        self.conn = pymysql.connect(host=host, user=user, password=password, port=prot, database=database,	
                                    cursorclass=pymysql.cursors.DictCursor, charset=charset)	
        self.cur = self.conn.cursor()	

	
    def __enter__(self):	
        return self.cur	

	
    def __exit__(self, exc_type, exc_val, exc_tb):	
        self.conn.commit()	
        self.cur.close()	
        self.conn.close()

我们在调用 with 的时候,首先代码会先跑到 init__ 方法,会初始化一些必要的对象。然后运行 _enter_ 方法,它的返回值会被赋值给 as 关键字后面的对象,就像栗子中的 as db。然后我们就可以通过拿到的对象进行一些增删改查的操作了。最后业务代码运行结束之后,会调用 __exit 方法,用来执行回收资源的操作。执行顺序是:

 
   

注意:enter 可以返回元组,且元组必须使用(),这样就可处理多个对象了。需要着重介绍一下的是  exit 方法,该方法中有3个参数,其功能如下:

exc_type: 错误的类型 	
exc_val: 错误类型对应的值 	
exc_tb: 代码中错误发生的位置

如果 exit 方法返回 false (不写返回值时,默认返回 false)则会将异常抛出给 with 语句之后的代码来处理异常。如果返回 True ,则需要在 __exit 方法中处理异常。

@contextlib.contextmanager	
def get_mysql_cur(database, host="localhost", user="root", prot=3306, password="root", charset="utf8mb4"):	
    conn = pymysql.connect(host=host, user=user, password=password, port=prot, database=database,	
                           cursorclass=pymysql.cursors.DictCursor, charset=charset)	
    cur = conn.cursor()	
    yield cur	
    conn.commit()	
    cur.close()	
    conn.close()

关于 contextlib ,主要是你要理解 yield 的用法,这里不过多讲解 yield。在 yield 之前的代码相当于 init 和 enter 的操作,yield 后面的值,相当于 enter 返回的值,yield 下面的代码相当于 exit 方法。


常见的 with 用例


file	
db	
socket	
decimal.Context	
thread.LockType	
threading.Lock	
threading.RLock	
threading.Condition	
threading.Semaphore	
threading.BoundedSemaphore

今天就讲到这,我们一步一个脚印,加油!

(*本文是Python大本营转载文章,转载请联系原作者)


社群福利

扫码添加小助手,回复:大会,加入2019 AI开发者大会福利群,每周一、三、五更新技术福利,还有不定期的抽奖活动~

640?wx_fmt=jpeg

推荐阅读

  • 开源之战

  • 谁偷偷删了你的微信?别慌!Python帮你都揪出来了

  • 吐血整理!140种Python标准库、第三方库和外部工具都有了

  • 如何用爬虫技术帮助孩子秒到心仪的幼儿园(基础篇)

  • Python传奇:30年崛起之路

  • 干货 | Python后台开发的高并发场景优化解决方案

  • 2019年最新华为、BAT、美团、头条、滴滴面试题目及答案汇总

  • 阿里巴巴杨群:高并发场景下Python的性能挑战

640?wx_fmt=png

你点的每个“在看”,我都认真当成了喜欢

你可能感兴趣的:(Python面试专题--with关键字与上下文管理)