试图用语句和上下文管理器来理解python

use*_*997 16 python contextmanager

我是新手,我只是想了解这个with陈述.我明白它应该替换try/ exceptblock.

现在假设我做了这样的事情:

try:
   name='rubicon'/2 # to raise an exception
except Exception as e:
   print "no not possible"
finally:
   print "Ok I caught you"
Run Code Online (Sandbox Code Playgroud)

如何用上下文管理器替换它?

Ale*_*lli 24

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
Run Code Online (Sandbox Code Playgroud)

return True部分是上下文管理器决定禁止异常的部分(正如您在except子句中不重新提升它一样).


Pau*_*ice 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
Run Code Online (Sandbox Code Playgroud)

为什么要编写上下文管理器的额外麻烦?代码重用.您可以在多个位置使用相同的上下文管理器,而无需复制异常处理.如果异常处理对于那种情况是唯一的,那么不要打扰上下文管理器.但是,如果相同的模式一次又一次地出现(或者如果它可能对您的用户而言,例如,关闭文件,解锁互斥锁),则值得额外麻烦.如果异常处理有点复杂,它也是一种简洁的模式,因为它将异常处理与代码流的主线分开.


Pab*_*ich 14

with在Python是用于包裹一组语句,你应该建立和摧毁或关闭的资源.它的方式与此类似try...finally,因为即使在异常之后也会执行finally子句.

上下文管理器是一个实现两种方法的对象:__enter____exit__.在with块之前和之后立即调用它们.

例如,看一下经典的open()例子:

with open('temp.txt', 'w') as f:
    f.write("Hi!")
Run Code Online (Sandbox Code Playgroud)

开返回一个File实现对象__enter__或多或少像return self__exit__喜欢self.close().


未来陆*_*投资人 7

上下文管理器的组件

  1. 您应该实现返回对象的__enter__方法
  2. 实现__exit__方法。

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

 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')
Run Code Online (Sandbox Code Playgroud)

在家里取东西时,应该打开一扇门,取东西然后关上门。

 with Door() as dr:
     dr.fetchsomethings()
Run Code Online (Sandbox Code Playgroud)

输出为:

the door was closed when you are not at home
I have opened the door
I have fetched somethings
pong!the door has closed
Run Code Online (Sandbox Code Playgroud)

说明

当您启动Door类时,它将调用__init__方法,该方法将显示“您不在家时门已关闭”,而__enter__方法将显示“我已经打开门”,并返回一个名为dr的门实例。当在块中调用self.fetchsomethings时,该方法将显示“我已获取了东西”。当该块完成时,上下文管理器将调用__exit__ 方法,并且将显示“ pong!门已关闭”。与关键字__enter____exit__一起使用将不会被调用!!!!


Bha*_*rel 5

with 语句或上下文管理器可以帮助您获得资源(尽管可能会使用更多资源)。

假设您打开了一个文件进行写入:

f = open(path, "w")
Run Code Online (Sandbox Code Playgroud)

您现在有了一个打开的文件句柄。在处理文件期间,没有其他程序可以写入该文件。为了让其他程序对其进行写入,必须关闭文件句柄:

f.close()
Run Code Online (Sandbox Code Playgroud)

但是,在关闭文件之前发生了错误:

f = open(path, "w")
data = 3/0  # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()
Run Code Online (Sandbox Code Playgroud)

现在将发生的是该函数或整个程序将退出,同时使文件保持打开状态。(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.
Run Code Online (Sandbox Code Playgroud)

with语句可以用于更多的事情。例如:threading.Lock()

lock = threading.Lock()
with lock:  # Lock is acquired
   do stuff...
# Lock is automatically released.
Run Code Online (Sandbox Code Playgroud)

用上下文管理器完成的几乎所有操作都可以完成,try: ... finally: ...但是上下文管理器更易于使用,更舒适,更具可读性,并且可以实现__enter____exit__提供易于使用的界面。


创建上下文管理器是通过在常规类中实现__enter__()并完成的__exit__()

__enter__()告诉上下文管理器启动时和__exit__()上下文管理器存在时的操作(__exit__()如果发生异常,则将异常提供给方法)

contextlib中可以找到创建上下文管理器的快捷方式。它将生成器包装为上下文管理器。