51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1236|回复: 2
打印 上一主题 下一主题

python中with...as的用法

[复制链接]
  • TA的每日心情
    无聊
    2024-9-27 10:07
  • 签到天数: 62 天

    连续签到: 1 天

    [LV.6]测试旅长

    跳转到指定楼层
    1#
    发表于 2018-2-7 16:02:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
          with…as,就是个python控制流语句,像 if ,while一样。 with…as语句是简化版的try except finally语句。

           那我们先理解一下try…except…finally语句是干啥的。实际上,try…except语句和try…finally语句是
    两种语句,用于不同的场景。但是当二者结合在一起时,可以“实现稳定性和灵活性更好的设计”。

            1. try…except语句
    用于处理程序执行过程中的异常情况,比如语法错误、从未定义变量上取值等等,也就是一些python
    程序本身引发的异常、报错。比如你在python下面输入 1 / 0:
    1. >>> 1/0
    2. Traceback (most recent call last):
    3.   File "<stdin>", line 1, in <module>
    4. ZeroDivisionError: division by zero
    复制代码
         系统会给你一个ZeroDivisionError的报错。
          说白了就是为了防止一些报错影响你的程序继续运行,就用try语句把它们抓出来(捕获)。
    try…except的标准格式:
    1. try:  
    2.     ## normal block  
    3. except A:  
    4.     ## exc A block  
    5. except:  
    6.     ## exc other block  
    7. else:  
    8.     ## noError block  
    复制代码
         程序执行流程是:

          –>执行normal block
          –>发现有A错误,执行 exc A block(即处理异常)
          –>结束
          如果没有A错误呢?
          –>执行normal block
          –>发现B错误,开始寻找匹配B的异常处理方法,发现A,跳过,发现except others(即except
    执行exc other block
          –>结束
          如果没有错误呢?
          –>执行normal block
          –>全程没有错误,跳入else 执行noError block
          –>结束
          Tips: 我们发现,一旦跳入了某条except语句,就会执行相应的异常处理方法(block),执行完毕就
    会结束。不会再返回try的normal block继续执行了。

    1. try:
    2.     a = 1 / 2 #a normal number/variable
    3.     print(a)
    4.     b = 1 / 0 # an abnormal number/variable
    5.     print(b)
    6.     c = 2 / 1 # a normal number/variable
    7.     print(c)
    8. except:
    9.     print("Error")
    复制代码
           输出:
    1. 0.5
    2. Error
    复制代码
         结果是,先打出了一个0,又打出了一个Error。就是把ZeroDivisionError错误捕获了。

          先执行try后面这一堆语句,由上至下:
          step1: a 正常,打印a. 于是打印出0.5 (python3.x以后都输出浮点数)
          step2: b, 不正常了,0 不能做除数,所以这是一个错误。直接跳到except报错去。于是打印了
    Error。
          step3: 其实没有step3,因为程序结束了。c是在错误发生之后的b语句后才出现,根本轮不到
    执行它。也就看不到打印出的c了

          但这还不是try/except的所有用法

          except后面还能跟表达式的! 所谓的表达式,就是错误的定义。也就是说,我们可以捕捉一
    些我们想要捕捉的异常。而不是什么异常都报出来。

          异常分为两类:

          python标准异常
          自定义异常
          我们先抛开自定义异常(因为涉及到类的概念),看看except都能捕捉到哪些python标准异
    常。请查看菜鸟笔记
    1. try:
    2.     a = 1 / 2
    3.     print(a)
    4.     print(m)  # 此处抛出python标准异常
    5.     b = 1 / 0 # 此后的语句不执行
    6.     print(b)
    7.     c = 2 / 1
    8.     print(c)
    9. except NameError:
    10.     print("Ops!!")
    11. except ZeroDivisionError:
    12.     print("Wrong math!!")
    13. except:
    14.     print("Error")
    复制代码
                                   输出:
    1. 0.5
    2. Ops!!
    复制代码
            当程序执行到print(m)的时候 发现了一个NameError: name 'm' is not defined,于是控制流去寻
    找匹配的except异常处理语句。发现了第一条匹配,执行对应block。执行完结束。
            2. try…finallly语句

           用于无论执行过程中有没有异常,都要执行清场工作。
           好的 现在我们看看他俩合在一起怎么用!!
    1. try:  
    2.     execution block  ##正常执行模块  
    3. except A:  
    4.     exc A block ##发生A错误时执行  
    5. except B:  
    6.     exc B block ##发生B错误时执行  
    7. except:  
    8.     other block ##发生除了A,B错误以外的其他错误时执行  
    9. else:  
    10.     if no exception, jump to here ##没有错误时执行  
    11. finally:  
    12.     final block  ##总是执行
    复制代码
         tips: 注意顺序不能乱,否则会有语法错误。如果用else就必须有except,否则会有语法错误。
    1. try:
    2.     a = 1 / 2
    3.     print(a)
    4.     print(m) # 抛出NameError异常
    5.     b = 1 / 0
    6.     print(b)  
    7.     c = 2 / 1
    8.     print(c)
    9. except NameError:
    10.     print("Ops!!")  # 捕获到异常
    11. except ZeroDivisionError:
    12.     print("Wrong math!!")
    13. except:
    14.     print("Error")
    15. else:
    16.     print("No error! yeah!")
    17. finally:      # 是否异常都执行该代码块
    18.     print("Successfully!")
    复制代码
           输出:
    1. 0.5
    2. Ops!!
    3. Successfully!
    复制代码
          try语句终于搞清楚了! 那么可以继续with…as的探险了

           3. with…as语句

           with as 语句的结构如下:
    1. with expression [as variable]:  
    2.     with-block  
    复制代码
         看这个结构我们可以获取至少两点信息 1. as可以省略 2. 有一个句块要执行

           所谓上下文管理协议,其实是指with后面跟的expression。这个expression一般都是一个类的实体。
    这个类的实体里面要包含有对__enter__和__exit__函数的定义才行。
           除了给类定义一些属性之外,还可以定义类的方法。也就是允许对类的内容有哪些操作,最直观
    的方法就是用dir()函数来看一个类的属性和方法。比如要查看字符串类有哪些属性和方法:
    1. >>> dir(str)
    2. ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    复制代码
         类,除了python内置的,当然还可以自己定义! 所以除了expression表示一些含有这两种方法的内
    置类,还可以自己定义类,让他们含有enter和exit方法。可能大家一直奇怪,为什么有的方法,比如
    上图中的'split' 'title'什么的都没有下划线,而又有很多,,比如__enter__和__exit__要写下划线呢?


           with…as语句执行顺序:

    –>首先执行expression里面的__enter__函数,它的返回值会赋给as后面的variable,想让它返回什么
    就返回什么,只要你知道怎么处理就可以了,如果不写as variable,返回值会被忽略。

    –>然后,开始执行with-block中的语句,不论成功失败(比如发生异常、错误,设置sys.exit()),在
    with-block执行完成后,会执行expression中的__exit__函数。

    当with...as语句中with-block被执行或者终止后,这个类对象应该做什么。如果这个码块执行成功,
    则exception_type,exception_val, trace的输入值都是null。如果码块出错了,就会变成像try/except
    /finally语句一样,exception_type, exception_val, trace 这三个值系统会分配值。

    这个和try finally函数有什么关系呢?其实,这样的过程等价于:
    1. try:  
    2.     执行 __enter__的内容  
    3.     执行 with_block.  
    4. finally:  
    5.     执行 __exit__内容  
    复制代码




    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2024-9-27 10:07
  • 签到天数: 62 天

    连续签到: 1 天

    [LV.6]测试旅长

    2#
     楼主| 发表于 2018-2-7 16:04:53 | 只看该作者
          那么__enter__和__exit__是怎么用的方法呢?我们直接来看一个栗子好了。 程序无错的例子:
    1. class Sample(object):             # object类是所有类最终都会继承的类
    2.     def __enter__(self):          # 类中函数第一个参数始终是self,表示创建的实例本身
    3.         print("In __enter__()")
    4.         return "Foo"

    5.     def __exit__(self, type, value, trace):
    6.         print("In __exit__()")


    7. def get_sample():
    8.     return Sample()


    9. with get_sample() as sample:
    10.     print("sample:", sample)


    11. print(Sample)    # 这个表示类本身   <class '__main__.Sample'>
    12. print(Sample())  # 这表示创建了一个匿名实例对象 <__main__.Sample object at 0x00000259369CF550>
    复制代码
          输出结果:
    1. In __enter__()
    2. sample: Foo
    3. In __exit__()
    4. <class '__main__.Sample'>
    5. <__main__.Sample object at 0x00000226EC5AF550>
    复制代码
          步骤分析:
    –> 调用get_sample()函数,返回Sample类的实例;
    –> 执行Sample类中的__enter__()方法,打印"In__enter_()"字符串,并将字符串“Foo”赋值给as后面
    的sample变量;
    –> 执行with-block码块,即打印"sample: %s"字符串,结果为"sample: Foo"
    –> 执行with-block码块结束,返回Sample类,执行类方法__exit__()。因为在执行with-block码块时并
    没有错误返回,所以type,value,trace这三个arguments都没有值。直接打印"In__exit__()"

    程序有错的例子:
    1. class Sample:
    2.     def __enter__(self):
    3.         return self

    4.     def __exit__(self, type, value, trace):
    5.         print("type:", type)
    6.         print("value:", value)
    7.         print("trace:", trace)

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


    11. with Sample() as sample:
    12.     sample.do_something()
    复制代码
         输出结果:
    1. type: <class 'ZeroDivisionError'>
    2. value: division by zero
    3. trace: <traceback object at 0x0000019B73153848>
    4. Traceback (most recent call last):
    5.   File "F:/机器学习/生物信息学/Code/first/hir.py", line 16, in <module>
    6.     sample.do_something()
    7.   File "F:/机器学习/生物信息学/Code/first/hir.py", line 11, in do_something
    8.     bar = 1 / 0
    9. ZeroDivisionError: division by zero
    复制代码
         步骤分析:
    –> 实例化Sample类,执行类方法__enter__(),返回值self也就是实例自己赋值给sample。即sample是
    Sample的一个实例(对象);
    –>执行with-block码块: 实例sample调用方法do_something();
    –>执行do_something()第一行 bar = 1 / 0,发现ZeroDivisionError,直接结束with-block代码块运行
    –>执行类方法__exit__(),带入ZeroDivisionError的错误信息值,也就是type,value, trace,并打印它们。

    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-27 15:36 , Processed in 0.067885 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表