我是新手,只是想了解 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().

上下文管理器的组件

  1. 您应该实施 __进入__ 返回对象的方法
  2. 实施 __出口__ 方法。

例子

我将举一个简单的示例,向您展示为什么我们需要上下文管理器。在中国新疆的冬季,您应该在打开门时立即关上门。如果您忘记关闭它,您会很冷。

 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. 。它将发电机作为上下文管理器包装。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top