• 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!
  • 相关阅读:
    sqlalchemy
    nginx配置文件,做多个项目代理
    pyspider
    Mysql原理+ 多实例 +表损坏
    Spring 学习-AOP
    java 基础 --- 动态代理和静态代理
    Spring 学习-IoC
    [转]字符编码笔记:ASCII,Unicode 和 UTF-8
    JVM(五) class类文件的结构
    数据结构(四)--- 红黑树(RedBlock-Tree)
  • 原文地址:https://www.cnblogs.com/xu-rui/p/6477271.html
Copyright © 2020-2023  润新知