首页 > 编程语言 > 详细

Python 中 with...as的用法

时间:2021-08-24 11:21:45      阅读:11      评论:0      收藏:0      [点我收藏+]


原文链接:

https://blog.csdn.net/qiqicos/article/details/79200089

https://blog.csdn.net/elevenqiao/article/details/6796653

 

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  

程序执行流程是:

 1 –>执行normal block
 2 –>发现有A错误,执行 exc A block(即处理异常)
 3 –>结束
 4 如果没有A错误呢?
 5 –>执行normal block
 6 –>发现B错误,开始寻找匹配B的异常处理方法,发现A,跳过,发现except others(即except:),执行exc other block
 7 –>结束
 8 如果没有错误呢?
 9 –>执行normal block
10 –>全程没有错误,跳入else 执行noError block
11 –>结束

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是一个控制流语句,跟if/for/while/try之类的是一类的,with可以用来简化try finally代码,看起来可以比try finally更清晰。这里新引入了一个"上下文管理协议"context management protocol,实现方法是为一个类定义__enter__和__exit__两个函数。with expresion as variable的执行过程是,首先执行__enter__函数,它的返回值会赋给as后面的variable,想让它返回什么就返回什么,只要你知道怎么处理就可以了,如果不写as variable,返回值会被忽略。

然后,开始执行with-block中的语句,不论成功失败(比如发生异常、错误,设置sys.exit()),在with-block执行完成后,会执行__exit__函数。这样的过程其实等价于:

1 try:
2     执行 __enter__的内容
3     执行 with_block.
4 finally:
5     执行 __exit__内容

只不过,现在把一部分代码封装成了__enter__函数,清理代码封装成__exit__函数。

所谓上下文管理协议,其实是指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__要写下划线呢?请参考博文http://blog.csdn.net/qiqicos/article/details/79208039

那么__enter____exit__是怎么用的方法呢?我们直接来看一个例子好了。

 1 class Sample(object):             # object类是所有类最终都会继承的类
 2     def __enter__(self):          # 类中函数第一个参数始终是self,表示创建的实例本身
 3         print("In __enter__()")
 4         return "Foo"
 5 
 6     def __exit__(self, type, value, trace):
 7         print("In __exit__()")
 8 
 9 
10 def get_sample():
11     return Sample()
12 
13 
14 with get_sample() as sample:
15     print("sample:", sample)
16 
17 
18 print(Sample)    # 这个表示类本身   <class ‘__main__.Sample‘>
19 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 
 5     def __exit__(self, type, value, trace):
 6         print("type:", type)
 7         print("value:", value)
 8         print("trace:", trace)
 9 
10     def do_something(self):
11         bar = 1 / 0
12         return bar + 10
13 
14 
15 with Sample() as sample:
16     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,并打印它们。

Python 中 with...as的用法

原文:https://www.cnblogs.com/lmj-sky/p/15179111.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!