python上下文管理,with语句

今天在网上看到一段代码,其中使用了with seam:初见不解其意,遂查询资料.

代码:

 1 #! /usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import time
 4 from random import random
 5 from threading import Thread,Semaphore
 6 
 7 sema = Semaphore(3)
 8 
 9 def foo(tid):
10     with sema:
11         print("{} acquire sema".format(tid))
12         wt = random() * 2
13         time.sleep(wt)
14     print("{} release sema".format(tid))
15 
16 threads = []
17 
18 for i in range(5):
19     t = Thread(target=foo,args=(i,))
20     threads.append(t)
21     t.start()
22 
23 for t in threads:
24     t.join()

查询 python核心编程第二版,其中有个章节,专门介绍了with语句和上下文管理.

with语句,在Python2.6正式启用,和try-except-finally 类似,with语句也是用来简化代码的.Python中,并非任意符号都可以使用with语句,with语句仅仅工作于支持上下文管理协议的对象.

with应用场景:打开文件,日志,数据库,线程资源,简单同步,数据库连接等等.

1 with context_expr [as var]:   ##context_expr:上下文表达式,[]可选
2     with_suite

能和with一起使用的成员列表:

1 file
2 decimal.Context
3 thread.LockType
4 threading.Lock
5 threading.RLock
6 threading.Condition
7 threading.Semaphore
8 threading.BoundedSemaphore

最最常见的with用法:

1 with open("file","r") as f:
for line in f:
2 pass

上面的代码都做了什么操作?

程序试图打开一个文本,如果一切正常,把文本对象赋值给f,然后用迭代器遍历文本中的每一行.当完成时,关闭文本.

无论在这段代码的开始,中间,还是结束时发生了异常,都会执行清理的代码,此外文件仍然被会自动的关闭.

先上一个最简单的代码:

 1 class Context:
 2     def __init__(self,name):
 3         self.name = name
 4     def __enter__(self):
 5         print("Begin.__enter__")
 6         return self
 7     def __exit__(self, exc_type, exc_val, exc_tb):
 8         print("End.__exit__")
 9     def context(self):
10         print("This is context ...{}".format(self.name))
11 
12 with Context("xurui") as context: ##如果带上 as 变量,那么__enter__()方法必须得返回一个东西,要不然会报错..
13     context.context()
14 with Context("xurui"):
15     Context("xurui").context()

演示代码:

class Sample:
    """
    ##执行__enter__方法,它将完成with语句块执行前的所有准备工作,如果with xx 后面带上参数,as val,那么__enter__返回值将赋值给
    val,否则,丢弃返回值"""
    def __enter__(self):
        print("In __enter__()")
        return "Foo"  ##返回"Foo"给as Sample中的Sample
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("In __exit__()")

def get_sample():
    print(type(Sample()))
    return Sample()

with get_sample() as Sample:
    print("sample:{}".format(Sample))

结果:
In __enter__()
sample:Foo
In __exit__()

但这都不是with的牛逼功能,with最强的地方,还是用来处理异常...

__exit__(),有三个参数,类型(异常类),值(异常实例),和回溯(回溯对象).

演示代码:

class Sample:
    """
    ##执行__enter__方法,它将完成with语句块执行前的所有准备工作,如果with xx 后面带上参数,as val,那么__enter__返回值将赋值给
    val,否则,丢弃返回值"""
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("type:{},
value:{},
trace:{}".format(exc_type,exc_val,exc_tb))

    def do_something(self):
        bar = 1 / 0
        return bar + 10

with Sample() as Sample:
    Sample.do_something()
    print("sample:{}".format(Sample))

结果:
type:<class 'ZeroDivisionError'>,
value:division by zero,
trace:<traceback object at 0x0000000001074CC8>
Traceback (most recent call last):
  File "C:/Users/xurui/PycharmProjects/q1/2017-03-01/error.py", line 55, in <module>
    Sample.do_something()
  File "C:/Users/xurui/PycharmProjects/q1/2017-03-01/error.py", line 51, in do_something
    bar = 1 / 0
ZeroDivisionError: division by zero
 1 import queue
 2 import contextlib
 3 
 4 
 5 @contextlib.contextmanager
 6 def worker_state(xxx, val):
 7     xxx.append(val)
 8     # print(xxx)
 9     try:
10         yield
11     finally:
12         xxx.remove(val)
13         # print(xxx)
14 
15 
16 q = queue.Queue()
17 li = []
18 q.put("xurui")
19 with worker_state(li, 1):
20     print("before", li)
21     q.get()
22 print("after", li)

自定义一个open文件

 1 import contextlib
 2 
 3 
 4 @contextlib.contextmanager
 5 def MyOpen(filename, mode):
 6     try:
 7         f = open(filename, mode, encoding='utf')
 8     except Exception as e:
 9         pass
10     else:
11         yield f   ##f return 给 as f的f
12     finally:
13         f.close()
14 
15 
16 with MyOpen("1.py", 'r') as f:
17     ret = f.readlines()
18     print(ret)
人生苦短,我用python!
原文地址:https://www.cnblogs.com/xu-rui/p/6477271.html