1、with操作符

在python中读写文件,可能需要这样的代码

try-finally读写文件

file_text = None
try:
file_text = open('./text', 'r')
print file_text.read()
except IOError, ex:
traceback.print_exc()
finally:
if file_text:
file_text.close()

同样,在python中使用线程锁,可能需要这样的代码

try-finally线程锁

lock = threading.Lock()
lock.acquire()
try:
pass
except Exception, ex:
traceback.print_exc()
finally:
lock.release()

可能你会觉得这种写法很不方便,python提供了with操作符,你可以这样操作

with读写文件

with open('./text', 'r') as file_text:
print file_text.read()

with线程锁

with lock:
pass

是不是方便多了。

其实,不只是lock和file可以使用with操作符。

实际上,任何对象,只要正确实现上下文管理,就可以使用with语句。实现上下文管理是通过 __enter__ 和 __exit__ 这两个方法实现的。

2、上下文管理

上下文管理可以为我们屏蔽上下文的复杂性。例如,我们实现一个类Cat,实现其__enter__和__exit__方法。

__enter__(self): 进入上下文管理器时调用此方法,其返回值将被放入with-as语句中as说明符指定的变量中。

__exit__(self,type,value,tb):离开上下文管理器调用此方法。如果有异常出现,type、value、tb分别为异常的类型、值和追踪信息。如果没有异常,

3个参数均设为None。此方法返回值为True或者False,分别指示被引发的异常得到了还是没有得到处理。如果返回False,引发的异常会被传递出上下文。

如下。

class Cat(object):

    def __init__(self, name):
self.name = name def __enter__(self):
print 'enter from Cat named %s' % self.name
return self def hello(self):
print 'hello, %s' % self.name def __exit__(self, exc_type, exc_val, exc_tb):
print 'exit from Cat named %s' % self.name

执行,并打印结果

with Cat('Tom') as tom:
tom.hello() enter from Cat named Tom
hello, Tom
exit from Cat named Tom

这里我们执行as tom获得了Cat类的一个实例,这是通过__enter__方法的返回得到的。

当然,我们可以管理多个,请注意进入和退出的顺序。

with Cat('Tom') as tom, Cat('Harry') as harry:
tom.hello()
harry.hello() enter from Cat named Tom
enter from Cat named Harry
hello, Tom
hello, Harry
exit from Cat named Harry
exit from Cat named Tom

3、contextmanager

可能你还是觉得实现__enter__和__exit__很麻烦。python提供了contextlib.contextmanager

让我们重写上面的例子,使用contextmanager

from contextlib import contextmanager as _contextmanager

@_contextmanager
def cat(name):
print 'enter cat named %s' % name
yield name
print 'exit cat named %s' % name

执行,并打印结果

with cat('Kitty') as kitty:
print 'hello, %s' % kitty enter cat named Kitty
hello, Kitty
exit cat named Kitty

as后面的实例,是通过yield语句返回的。这里是返回了一个字符串。

当然,同样支持管理多个实例

with cat('Kitty') as kitty, cat('Tom') as tom:
print 'hello, %s' % kitty
print 'hello, %s' % tom enter cat named Kitty
enter cat named Tom
hello, Kitty
hello, Tom
exit cat named Tom
exit cat named Kitty

4、最后给出一个实例

使用上下文管理器实现redis分布式锁

# -*- coding:utf-8 -*-
from __future__ import print_function
import redis
import time
import multiprocessing
from contextlib import contextmanager as _contextmanager
# 简单创建redis的客户端
r = redis.Redis(host='localhost', port=6379, db=0) # 分布式锁实现
# finally中验证本线程是否获得锁, 是为了防止误删别的线程获取的锁
@_contextmanager
def dist_lock(client, key):
dist_lock_key = 'lock:%s' % key
is_acquire_lock = False
try:
is_acquire_lock = _acquire_lock(client, dist_lock_key)
yield
finally:
if is_acquire_lock:
_release_lock(client, dist_lock_key) # 尝试获取锁
# 成功: 返回True, 失败: 抛出异常
# 使用set nx ex原语, 使得setnx和expire操作成为原子操作
def _acquire_lock(client, key):
is_lock = r.set(key, 1, nx=True, ex=10)
if not is_lock:
raise Exception("already locked!")
return is_lock # 释放锁
# 简单删除key
# 如果删除失败, 锁也会通过expire时间超时
def _release_lock(client, key):
client.delete(key) # 测试函数
# 获取锁成功, 打印成功, 并持有锁3s
# 获取锁失败, 直接打印
def func():
while 1:
try:
with dist_lock(r, 'key'):
print("*", end='')
time.sleep(3)
except Exception, ex:
print('!', end='') # 多进程启动
# 这种模式下, 线程锁无效, 可以验证分布式锁
process_list = list()
for i in range(2):
process_list.append(multiprocessing.Process(target=func))
for process in process_list:
process.start()
for process in process_list:
process.join()

python contextlib 上下文管理器的更多相关文章

  1. 谈一谈Python的上下文管理器

    经常在Python代码中看到with语句,仔细分析下,会发现这个with语句功能好强,可以自动关闭资源.这个在Python中叫上下文管理器Context Manager.那我们要怎么用它,什么时候用它 ...

  2. 【Python】 上下文管理器和contextlib

    上下文管理器 一直对python中的上下文管理比较迷惑,趁着今天研究SQLAlchemy顺便看了一下,感觉稍微清楚了一点.http://www.cnblogs.com/chenny7/p/421344 ...

  3. python 黑魔法 ---上下文管理器(contextor)

    所谓上下文 计算机上下文(Context)对于我而言,一直是一个很抽象的名词.就像形而上一样,经常听见有人说,但是无法和现实认知世界相结合. 最直观的上下文,莫过于小学的语文课,经常会问联系上下文,推 ...

  4. Python 的上下文管理器是怎么设计的?

    花下猫语:最近,我在看 Python 3.10 版本的更新内容时,发现有一个关于上下文管理器的小更新,然后,突然发现上下文管理器的设计 PEP 竟然还没人翻译过!于是,我断断续续花了两周时间,终于把这 ...

  5. python使用上下文管理器实现sqlite3事务机制

    如题,本文记录如何使用python上下文管理器的方式管理sqlite3的句柄创建和释放以及事务机制. 1.python上下文管理(with) python上下文管理(context),解决的是这样一类 ...

  6. (转)contextlib — 上下文管理器工具

    原文:https://pythoncaff.com/docs/pymotw/contextlib-context-manager-tool/95 这是一篇社区协同翻译的文章,你可以点击右边区块信息里的 ...

  7. python的上下文管理器-1

    reference:https://zhuanlan.zhihu.com/p/26487659 来看看如何正确关闭一个文件. 普通版: def m1(): f = open("output. ...

  8. contextlib 上下文管理器

    在Python中,读写文件这样的资源要特别注意,必须在使用完毕后正确关闭它们.正确关闭文件资源的一个方法是使用try...finally: try: f = open('/path/to/file', ...

  9. python的上下文管理器

    直接上代码: f = open('123.txt','w') try: f.write('hello world') except Exception: pass finally: f.close() ...

随机推荐

  1. CSS3弹性盒模型 display:box

    刚开始做网页时就有一个困惑,为什么display:block只能垂直排列,如果要水平排列就要使用float:left等方式.这种方法最难受的当然是当子元素的数量改变时,需要去修改子元素的宽度使重新适应 ...

  2. MPLS LDP随堂笔记1

    LDP 的使用原因(对于不同协议来说) LDP的四大功能 发现邻居 hello 5s 15s 224.0.0.2 发现邻居关系 R1 UDP 646端口 R2 UDP 646端口 此时形成邻居 建立邻 ...

  3. 测试驱动开发(TDD)

    测试驱动开发的基本概念 为什么会出现测试驱动开发 当有一个新的任务时,往往第一个念头就是如何去实现它呢? 拿到任务就开始编码,一边写,变修改和设计 我已经调试了好几遍,应该不会有问题了,好了,先休息一 ...

  4. win8下安装VC6出现兼容性问题的解决办法

    重装系统之后(win8的系统),发现VC6安装出现兼容性问题,花了一些时间解决,有出现的问题都差不多在下面链接的总结中,写的很详细: http://www.docin.com/p-1126120829 ...

  5. 《Java程序设计》第1周学习总结

    1.本周本章学习总结 感觉装环境和基础语言也没什么好总结的,就谈谈我对java的认识. 接触的语言也不多,c语言,python.去年科研立项立了个安卓开发的项.也有去学了一阶段java.由于种种原因没 ...

  6. 201521123067 《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 2. 书面作业 Q1:clone方法 1.1 Object ...

  7. 201521123070 《JAVA程序设计》第1周学习总结

    本周学习总结 1.认识了三大平台Java SE.Java EE.Java ME. 2.认识了解了JDK,JVM与JRE,且熟悉JDK的操作并下载安装. 3.学会用博客写作业了. 书面作业 Q1.为什么 ...

  8. 201521123106《java程序设计》第一周学习总结

    1.本章学习总结 认识了java语言,了解了java的历史,学习了各种java相关文件的使用,能够进行基本的程序操作,学会了使用博客.码云. 2.书面作业 1.为什么java程序可以跨平台运行?执行j ...

  9. 201521123011《Java程序设计》第10周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异常.多线程 1.finally 题目4-2 1.1 截图你的提交结果(出 ...

  10. 201521123027<java程序设计>第14周作业总结

    1.本周作业总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2.书面作业 Q1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己 ...