我是新手,我只是想了解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"
如何用上下文管理器替换它?
答案 0 :(得分:23)
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
子句中没有重新提升它一样)。
答案 1 :(得分:18)
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
为什么要编写上下文管理器的额外麻烦?代码重用。您可以在多个位置使用相同的上下文管理器,而无需复制异常处理。如果异常处理对于那种情况是唯一的,那么不要打扰上下文管理器。但是,如果相同的模式一次又一次地出现(或者如果它可能对您的用户而言,例如,关闭文件,解锁互斥锁),则值得额外麻烦。如果异常处理有点复杂,它也是一个简洁的模式,因为它将异常处理与代码流的主线分开。
答案 2 :(得分:14)
Python中的with
旨在包装一组您应该设置,销毁或关闭资源的语句。在这方面,它与try...finally
类似,因为即使在异常之后也会执行finally子句。
上下文管理器是一个实现两种方法的对象:__enter__
和__exit__
。这些在with
块之前和之后立即被调用。
例如,看一下经典的open()
示例:
with open('temp.txt', 'w') as f:
f.write("Hi!")
Open会返回一个File
对象,该对象实现__enter__
或多或少像return self
和__exit__
,如self.close()
。
答案 3 :(得分:6)
1.您应该实现一个返回对象的 __ enter __ 方法 2.实现 __退出__ 方法
我将举一个简单的例子向您展示我们为什么需要上下文管理器。在中国新疆的冬天,当您打开门时,应立即关上门。如果您忘记了
关闭它,你会得到***。
class Door:
def __init__(self):
self.doorstatus='the door was closed when you are not in 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 in home
i have opened the door
i have fetched somethings
pong!the door has closed
当您启动Door类时,它将调用将要打印的 __ init __ 方法 "当你不在家时,门被关闭了#34;和 __输入__ 方法将打印"我打开了大门"并返回一个名为dr的门实例。当使用块调用 self.fetchsomethings 时,该方法将打印"我已经取出了某些东西"。当块完成时。上下文管理器将调用 __ exit __ 方法,它将打印" pong!门关闭"当你不使用时 关键字, __输入__ 和 __退出__ 将不会被调用!!!!
答案 4 :(得分:5)
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在终止时清除句柄,句柄与程序一起释放,但你不应该依赖它)
with语句确保一旦你留下它的缩进,它就会关闭文件句柄:
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__
和{{ 1}}提供易于使用的界面。
通过在普通班级中实施__enter__()
和__exit__()
来创建上下文管理器。
__exit__
告诉上下文管理器启动时要执行的操作以及上下文管理器存在时__enter__()
(如果发生异常,则为__exit__()
方法提供异常)
可以在contextlib中找到创建上下文管理器的快捷方式。它将生成器包装为上下文管理器。