上下文管理器
定义
语法
try:
file = open('Cp1.ipynb', 'r', encoding='utf8')
content = file.read()
finally:
file.close()
with open('Cp1.ipynb', 'r', encoding='utf8') as f:
content = f.read()
enter 与 exit
class ContextManager:
def __init__(self):
self._entered = False
def __enter__(self):
self._entered = True
return self
def __exit__(self, exc_type, exc_instance, traceback):
self._entered = False
c1 = ContextManager()
print(c1._entered)
with ContextManager() as c2:
print(c2._entered)
False
True
异常处理
何时写上下文处理器
资源清理
避免重复
传播异常
class BubbleExc:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_instance, traceback):
print('in __exit__')
if exc_instance:
print(exc_instance)
return False
with BubbleExc():
5+5
with BubbleExc():
5 / 0
in __exit__
in __exit__
division by zero
终止异常
class SuppressExc:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_instance, traceback):
print('in __exit__')
if exc_instance:
print(exc_instance)
return True
with SuppressExc():
5+5
with SuppressExc():
5 / 0
print(1)
in __exit__
in __exit__
division by zero
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_13988/2733532279.py in <module>
13
14 with SuppressExc():
---> 15 5 / 0
16 print(1)
ZeroDivisionError: division by zero
with SuppressExc():
try:
5 / 0
except ZeroDivisionError:
print('catch exception by context')
print(1)
catch exception by context
1
in __exit__
处理特定异常类
class HandleError:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_instance, traceback):
if exc_type is None:
return True
if issubclass(exc_type, ValueError):
print('__exit__ handle a Value Error')
return True
return False
with HandleError():
raise ValueError('test')
with HandleError():
raise RuntimeError()
__exit__ handle a Value Error
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_13988/2716100519.py in <module>
15
16 with HandleError():
---> 17 raise RuntimeError()
RuntimeError:
不包括的子类
class ValueErrorSubclass(ValueError):
pass
class HandleError:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_instance, traceback):
if exc_type is None:
return True
if exc_type == ValueError:
print('__exit__ handle a Value Error')
return True
return False
with HandleError():
raise ValueError()
with HandleError():
raise ValueErrorSubclass()
__exit__ handle a Value Error
---------------------------------------------------------------------------
ValueErrorSubclass Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_13988/2102615219.py in <module>
20
21 with HandleError():
---> 22 raise ValueErrorSubclass()
ValueErrorSubclass:
基于属性的异常处理
import subprocess
class ShellException(Exception):
def __init__(self, code, stdout='', stderr=''):
self.code = code
self.stdout = stdout
self.stderr = stderr
def __str__(self):
return f'exit code {self.code}- {self.stderr}'
def run_command(command):
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.wait()
stdout, stderr = proc.communicate()
if proc.returncode > 0:
raise ShellException(proc.returncode, stdout, stderr)
return stdout
run_command('rm 123.txt')
---------------------------------------------------------------------------
ShellException Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_13988/2086617344.py in <module>
20 return stdout
21
---> 22 run_command('rm 123.txt')
~\AppData\Local\Temp/ipykernel_13988/2086617344.py in run_command(command)
17
18 if proc.returncode > 0:
---> 19 raise ShellException(proc.returncode, stdout, stderr)
20 return stdout
21
ShellException: exit code 1- b"rm: cannot remove '123.txt': No such file or directory\n"
更简单的语法
import os
import contextlib
@contextlib.contextmanager
def accept_error_codes(*codes):
try:
yield
except ShellException as exc_instance:
if exc_instance.code not in codes:
raise
print('get code', exc_instance.code)
pass
with accept_error_codes(1):
run_command('rm 123.txt')
get code 1