Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python with 修饰符 #25

Open
sfPPP opened this issue Aug 16, 2018 · 0 comments
Open

python with 修饰符 #25

sfPPP opened this issue Aug 16, 2018 · 0 comments

Comments

@sfPPP
Copy link
Owner

sfPPP commented Aug 16, 2018

python中with可以明显改进代码友好度

with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等


假设要对一个文件进行操作

           with open(os.path.join(self.SAMPLE_ROOT, sample_file), 'r') as f:
                sample_content = f.read()

而如果我们用try catch finally

somefile = open(r'somefileName')
try:
    for line in somefile:
        print line
        # ...more code
finally:
    somefile.close()

代码显得没那么友好

with 语句的执行过程

context_manager = context_expression
exit = type(context_manager).__exit__  
value = type(context_manager).__enter__(context_manager)
exc = True   # True 表示正常执行,即便有异常也忽略;False 表示重新抛出异常,需要对异常进行处理
try:
    try:
        target = value  # 如果使用了 as 子句
        with-body     # 执行 with-body
    except:
        # 执行过程中有异常发生
        exc = False
        # 如果 __exit__ 返回 True,则异常被忽略;如果返回 False,则重新抛出异常
        # 由外层代码对异常进行处理
        if not exit(context_manager, *sys.exc_info()):
            raise
finally:
    # 正常退出,或者通过 statement-body 中的 break/continue/return 语句退出
    # 或者忽略异常退出
    if exc:
        exit(context_manager, None, None, None) 
    # 缺省返回 None,None 在布尔上下文中看做是 False

执行 context_expression,生成上下文管理器 context_manager
调用上下文管理器的 __enter__() 方法;如果使用了 as 子句,则将 __enter__() 方法的返回值赋值给 as 子句中的 target(s)
执行语句体 with-body
不管是否执行过程中是否发生了异常,执行上下文管理器的 __exit__() 方法,__exit__() 方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句 break/continue/return,则以 None 作为参数调用 __exit__(None, None, None) ;如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用 __exit__(exc_type, exc_value, exc_traceback)
出现异常时,如果 __exit__(type, value, traceback) 返回 False,则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理

我们自己的类也可以使用with, 只要给这个类增加两个函数__enter__, __exit__即可:

>>> class A:
	def __enter__(self):
		print 'in enter'
	def __exit__(self, e_t, e_v, t_b):
		print 'in exit'
 
>>> with A() as a:
	print 'in with'
 
in enter
in with
in exit

python库中还有一个模块contextlib,使你不用构造含有__enter__, __exit__的类就可以使用with:

>>> from contextlib import contextmanager
>>> from __future__ import with_statement
>>> @contextmanager
... def context():
...     print 'entering the zone'
...     try:
...         yield
...     except Exception, e:
...         print 'with an error %s'%e
...         raise e
...     else:
...         print 'with no error'
...
>>> with context():
...     print '----in context call------'
...
entering the zone
----in context call------
with no error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant