python中with...as的用法

with…as,就是个python控制流语句,像 if ,while一样。
with…as语句是简化版的try except finally语句。

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

try…except语句

用于处理程序执行过程中的异常情况,比如语法错误、从未定义变量上取值等等,也就是一些python程序本身引发的异常、报错。比如你在python下面输入 1 / 0:

>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
系统会给你一个ZeroDivisionError的报错。

说白了就是为了防止一些报错影响你的程序继续运行,就用try语句把它们抓出来(捕获)。
try…except的标准格式:

try:  
    ## normal block  
except A:  
    ## exc A block  
except:  
    ## exc other block  
else:  
    ## 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继续执行了。

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

try…finallly语句

用于无论执行过程中有没有异常,都要执行清场工作。好的 现在我们看看他俩合在一起怎么用!!

try:  
    execution block  ##正常执行模块  
except A:  
    exc A block ##发生A错误时执行  
except B:  
    exc B block ##发生B错误时执行  
except:  
    other block ##发生除了A,B错误以外的其他错误时执行  
else:  
    if no exception, jump to here ##没有错误时执行  
finally:  
    final block  ##总是执行  

tips: 注意顺序不能乱,否则会有语法错误。如果用else就必须有except,否则会有语法错误。

try:
    a = 1 / 2
    print(a)
    print(m) # 抛出NameError异常
    b = 1 / 0
    print(b)  
    c = 2 / 1
    print(c)
except NameError:
    print("Ops!!")  # 捕获到异常
except ZeroDivisionError:
    print("Wrong math!!")
except:
    print("Error")
else:
    print("No error! yeah!")
finally:      # 是否异常都执行该代码块
    print("Successfully!")

输出:

0.5
Ops!!
Successfully!
1
2
3

try语句终于搞清楚了! 那么可以继续with…as的探险了

with…as语句

with as 语句的结构如下:

with expression [as variable]:  
    with-block  

看这个结构我们可以获取至少两点信息 1. as可以省略 2. 有一个句块要执行

所谓上下文管理协议,其实是指with后面跟的expression。这个expression一般都是一个类的实体。这个类的实体里面要包含有对__enter__和__exit__函数的定义才行。

除了给类定义一些属性之外,还可以定义类的方法。也就是允许对类的内容有哪些操作,最直观的方法就是用dir()函数来看一个类的属性和方法。比如要查看字符串类有哪些属性和方法:

>>> dir(str)
['__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方法。

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函数有什么关系呢?其实,这样的过程等价于:

try:  
    执行 __enter__的内容  
    执行 with_block.  
finally:  
    执行 __exit__内容  

那么__enter__和__exit__是怎么用的方法呢?我们直接来看一个栗子好了。
程序无错的例子:

class Sample(object):             # object类是所有类最终都会继承的类
    def __enter__(self):          # 类中函数第一个参数始终是self,表示创建的实例本身
        print("In __enter__()")
        return "Foo"

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

def get_sample():
    return Sample()

with get_sample() as sample:
    print("sample:", sample)

print(Sample)    # 这个表示类本身   <class '__main__.Sample'>
print(Sample())  # 这表示创建了一个匿名实例对象 <__main__.Sample object at 0x00000259369CF550>

输出结果:

In __enter__()
sample: Foo
In __exit__()
<class '__main__.Sample'>
<__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__()"

程序有错的例子:

class Sample:
    def __enter__(self):
        return self

    def __exit__(self, type, value, trace):
        print("type:", type)
        print("value:", value)
        print("trace:", trace)

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

with Sample() as sample:
    sample.do_something()

输出结果:

type: <class 'ZeroDivisionError'>
value: division by zero
trace: <traceback object at 0x0000019B73153848>
Traceback (most recent call last):
  File "F:/机器学习/生物信息学/Code/first/hir.py", line 16, in <module>
    sample.do_something()
  File "F:/机器学习/生物信息学/Code/first/hir.py", line 11, in do_something
    bar = 1 / 0
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,并打印它们。

可以和with 一起工作的对象列表

  1. fie
  2. decimal.Context
  3. thread.LockType
  4. thread.RLock
  5. thread.Condition
  6. thread.Semaphore

作者:远方_Eden
来源:CSDN
原文:https://blog.csdn.net/qiqicos/article/details/79200089

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值