题
我是新手,只是想了解 with
陈述。我知道它应该替换 try
/except
堵塞。
现在假设我做这样的事情:
try:
name='rubicon'/2 # to raise an exception
except Exception as e:
print "no not possible"
finally:
print "Ok I caught you"
如何用上下文经理替换它?
解决方案
with
并没有真正取代 try
/except
, , 反而, try
/finally
. 。还是你 能够 使上下文管理器在异常情况下做一些不同的事情:
class Mgr(object):
def __enter__(self): pass
def __exit__(self, ext, exv, trb):
if ext is not None: print "no not possible"
print "OK I caught you"
return True
with Mgr():
name='rubicon'/2 #to raise an exception
这 return True
部分是上下文经理决定抑制异常的地方(就像您不重新升级的那样 except
条款)。
其他提示
这 ContextLib.ContextManager 功能装饰器提供了一种方便的方式来提供上下文经理,而无需编写完整的 ContextManager
自己的班级(与 __enter__
和 __exit__
方法,因此您不必记住对 __exit__
方法,或 __exit__
方法必须 return True
为了抑制例外)。相反,您用单个编写功能 yield
在您想要的 with
运行的块,您会捕获任何例外(有效来自 yield
)如往常。
from contextlib import contextmanager
@contextmanager
def handler():
# Put here what would ordinarily go in the `__enter__` method
# In this case, there's nothing to do
try:
yield # You can return something if you want, that gets picked up in the 'as'
except Exception as e:
print "no not possible"
finally:
print "Ok I caught you"
with handler():
name='rubicon'/2 #to raise an exception
为什么要撰写上下文经理的额外麻烦?代码重复使用。您可以在多个位置使用相同的上下文管理器,而无需复制异常处理。如果异常处理是这种情况所独有的,则不要为上下文经理打扰。但是,如果相同的模式一次又一次地播种(或者它可能适合您的用户,例如,关闭文件,解锁互斥品),则值得额外的麻烦。如果异常处理有点复杂,它也是一种整洁的模式,因为它将异常处理与代码流的主线分开。
这 with
在Python中,旨在包装一组陈述,您应该在其中设置并销毁或关闭资源。它以类似于 try...finally
在这方面,即使在例外,也将执行最终条款。
上下文管理器是实现两种方法的对象: __enter__
和 __exit__
. 。这些是在(分别)之前和之后(分别)调用的 with
堵塞。
例如,看看经典 open()
例子:
with open('temp.txt', 'w') as f:
f.write("Hi!")
公开回报a File
实现的对象 __enter__
或多或少 return self
和 __exit__
像 self.close()
.
上下文管理器的组件
- 您应该实施 __进入__ 返回对象的方法
- 实施 __出口__ 方法。
例子
我将举一个简单的示例,向您展示为什么我们需要上下文管理器。在中国新疆的冬季,您应该在打开门时立即关上门。如果您忘记关闭它,您会很冷。
class Door:
def __init__(self):
self.doorstatus='the door was closed when you are not at home'
print(self.doorstatus)
def __enter__(self):
print('I have opened the door')
return self
def __exit__(self,*args):
print('pong!the door has closed')
def fetchsomethings(self):
print('I have fetched somethings')
当家里拿东西时,您应该打开一扇门,拿起些东西并关上门。
with Door() as dr:
dr.fetchsomethings()
输出是:
the door was closed when you are not at home
I have opened the door
I have fetched somethings
pong!the door has closed
解释
当您开始门课时,它将致电 __在里面__ 将打印“当您不在家里时关门的门”的方法 __进入__ 将打印“我打开门”并返回一个名为DR的门的方法。打电话时 自我 在块中,该方法将打印“我已经提取了一些东西”。块完成后。上下文经理将调用 __出口__方法,它将打印“乒乓球!门已经关闭”。当您不使用关键字时,__进入__和 __出口__ 不会被调用!
with
声明或上下文经理在那里有助于资源(尽管可以使用更多)。
假设您打开了一个文件供书写:
f = open(path, "w")
您现在有一个打开的文件句柄。在处理文件期间,没有其他程序可以写入它。为了让其他程序写入它,您必须关闭文件句柄:
f.close()
但是,在关闭文件之前发生错误:
f = open(path, "w")
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()
现在将发生的事情是,在将文件留下打开的手柄时,功能或整个程序将退出。 (Cpython在终止和手柄上清洁手柄与程序一起释放,但您不应该指望)
a语句可确保一旦您离开它的缩进,它将关闭文件句柄:
with open(path, "w") as f:
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
# In here the file is already closed automatically, no matter what happened.
with
陈述可以用于更多的东西。例如: threading.Lock()
lock = threading.Lock()
with lock: # Lock is acquired
do stuff...
# Lock is automatically released.
几乎可以使用上下文经理完成的一切 try: ... finally: ...
但是上下文经理使用更好,更舒适,更可读性,并且通过实施 __enter__
和 __exit__
提供易于使用的接口。
创建上下文经理是通过实施来完成的 __enter__()
和 __exit__()
在正常类中。
__enter__()
告诉上下文管理器启动时该怎么办 __exit__()
当存在上下文经理时(给予例外 __exit__()
方法如果发生例外)
可以在创建上下文经理的快捷方式中找到 contextlib. 。它将发电机作为上下文管理器包装。