通过语句和上下文管理器了解 Python

发布于 2024-09-19 10:17:48 字数 333 浏览 5 评论 0原文

我试图理解 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.")

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

I am trying to understand the with statement. I understand that it is supposed to replace the try/except block.

Now suppose I do something like this:

try:
   name = "rubicon" / 2  # to raise an exception
except Exception as e:
   print("No, not possible.")
finally:
   print("OK, I caught you.")

How do I replace this with a context manager?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

我要还你自由 2024-09-26 10:17:48

contextlib.contextmanager 函数装饰器提供一种提供上下文管理器的便捷方法,无需编写您自己的成熟的 ContextManager 类(使用 __enter__ 和 __exit__ 方法,因此您不必记住 __exit__ 方法的参数,或者 __exit__ 方法必须返回 True 才能抑制异常)。相反,您可以在希望 with 块运行时编写一个具有单个 yield 的函数,并捕获任何异常(实际上来自 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

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

The contextlib.contextmanager function decorator provides a handy way of providing a context manager without the need to write a full-fledged ContextManager class of your own (with __enter__ and __exit__ methods, so you don't have to remember the arguments to the __exit__ method, or that the __exit__ method must return True in order to suppress the exception). Instead, you write a function with a single yield at the point you want the with block to run, and you trap any exceptions (that effectively come from the yield) as you normally would.

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

Why go to the extra trouble of writing a context manager? Code re-use. You can use the same context manager in multiple places, without having to duplicate the exception handling. If the exception handling is unique to that situation, then don't bother with a context manager. But if the same pattern crops up again and again (or if it might for your users, e.g., closing a file, unlocking a mutex), it's worth the extra trouble. It's also a neat pattern to use if the exception handling is a bit complicated, as it separates the exception handling from the main line of code flow.

装迷糊 2024-09-26 10:17:48

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

返回 True 部分是上下文管理器决定抑制异常的地方(如您可以通过不在 except 子句中重新引发它来实现)。

with doesn't really replace try/except, but, rather, try/finally. Still, you can make a context manager do something different in exception cases from non-exception ones:

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

The return True part is where the context manager decides to suppress the exception (as you do by not re-raising it in your except clause).

长不大的小祸害 2024-09-26 10:17:48

Python 中的 with 旨在包装一组应在其中设置、销毁或关闭资源的语句。在这方面,它与 try...finally 类似,因为即使在异常之后,finally 子句也会被执行。

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

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

with open('temp.txt', 'w') as f:
    f.write("Hi!")

Open 返回一个 File 对象,该对象或多或少类似于 实现 __enter__self.close()一样返回self__exit__

The with in Python is intended for wrapping a set of statements where you should set up and destroy or close resources. It is in a way similar to try...finally in that regard as the finally clause will be executed even after an exception.

A context manager is an object that implements two methods: __enter__ and __exit__. Those are called immediately before and after (respectively) the with block.

For instance, take a look at the classic open() example:

with open('temp.txt', 'w') as f:
    f.write("Hi!")

Open returns a File object that implements __enter__ more or less like return self and __exit__ like self.close().

停滞 2024-09-26 10:17:48

上下文管理器的组件

  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')

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

 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

解释

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

The Components of Context Manager

  1. You should implement an __enter__ method that returns an object
  2. Implement a __exit__ method.

Example

I will give a simple example to show you why we need a context manager. During the winter of Xinjiang, China, you should close a door immediately when you open a door. if you forget to close it, you will get cold.

 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')

when fetch things at home, you should open a door, fetch somethings and close the door.

 with Door() as dr:
     dr.fetchsomethings()

the output is:

the door was closed when you are not at home
I have opened the door
I have fetched somethings
pong!the door has closed

Explanation

when you initiate a Door class, it will call __init__ method that will print
"the door was closed when you are not in home" and __enter__ method that will print "I have opened the door" and return a door instance called dr. when call self.fetchsomethings in with block, the method will print "I have fetched somethings".when the block is finished.the context manager will invoke __exit__
method and it will print "pong!the door has closed" .when you do not use with
keyword ,__enter__and __exit__ will not be invoked!!!!

揽清风入怀 2024-09-26 10:17:48

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__ 和 __exit__ 提供了一个易于使用的界面。


创建上下文管理器是通过实现 __enter__() 来完成的__exit__() 在普通课堂上。

__enter__() 告诉当上下文管理器启动时要做什么,以及 __exit__() 当上下文管理器存在时要做什么(给 __exit__() 提供异常> 方法(如果发生异常)

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

with statements or context managers are there to aid with resources (although may be used for much more).

Let's say you opened a file for writing:

f = open(path, "w")

You now have an open file handle. During the handling of your file, no other program can write to it. In order to let other programs write to it, you must close the file handle:

f.close()

But, before closing your file an error occured:

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

What will happen now is that the function or entire program will exit, while leaving your file with an open handle. (CPython cleans handles on termination and handles are freed together with a program but you shouldn't count on that)

A with statement ensures that as soon as you leave it's indentation, it will close the file handle:

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 statements may be used for many more things. For example: threading.Lock()

lock = threading.Lock()
with lock:  # Lock is acquired
   do stuff...
# Lock is automatically released.

Almost everything done with a context manager can be done with try: ... finally: ... but context managers are nicer to use, more comfortable, more readable and by implementing __enter__ and __exit__ provide an easy to use interface.


Creating context managers is done by implementing __enter__() and __exit__() in a normal class.

__enter__() tells what to do when a context manager starts and __exit__() when a context manager exists (giving the exception to the __exit__() method if an exception occurred)

A shortcut for creating context managers can be found in contextlib. It wraps a generator as a context manager.

满意归宿 2024-09-26 10:17:48

管理资源:在任何编程语言中,文件操作或数据库连接等资源的使用都很常见。但这些资源的供应是有限的。因此,主要问题在于如何确保这些资源在使用后得到释放。如果不释放它们,则会导致资源泄漏,并可能导致系统变慢或崩溃。如果用户有一个自动设置和拆除资源的机制,那将会非常有帮助。在Python中,它可以通过使用上下文管理器来实现,上下文管理器有助于正确处理资源。执行文件操作的最常见方法是使用如下所示的关键字:

 # Python program showing a use of with keyword
 with open("test.txt") as f:  
     data = f.read()

打开文件时,会消耗文件描述符,这是一种有限的资源。一个进程一次只能打开一定数量的文件。下面的程序演示了这一点。

file_descriptors = []
for x in range(100000):
    file_descriptors.append(open('test.txt', 'w'))

它导致错误:OSError: [Errno 24] Too much open files: 'test.txt'

Python 提供了一种简单的方法来管理资源:上下文管理器。使用 with 关键字。当它被评估时,它应该产生一个执行上下文管理的对象。上下文管理器可以使用类或函数(带有装饰器)来编写。

创建上下文管理器:当使用类创建上下文管理器时,用户需要确保该类具有方法:__enter__()__exit__()__enter__() 返回需要管理的资源,__exit__() 不返回任何内容,但执行清理操作。首先,让我们创建一个名为 ContextManager 的简单类,以了解使用类创建上下文管理器的基本结构,如下所示:

# Python program creating a context manager 
class ContextManager():
    def __init__(self):
        print('init method called')
         
    def __enter__(self):
        print('enter method called')
        return self
     
    def __exit__(self, exc_type, exc_value, exc_traceback):
        print('exit method called')
 
with ContextManager() as manager:
    print('with statement block')

Output:
init method called
enter method called
with statement block
exit method called

在本例中,创建了一个 ContextManager 对象。这被分配给关键字 ie manager 之后的变量。运行上述程序时,将按顺序执行以下内容:

  • __init__()
  • __enter__()
  • 语句主体(with 块内的代码)
  • __exit__()[该方法中的参数用于管理异常]

Managing Resources: In any programming language, the usage of resources like file operations or database connections is very common. But these resources are limited in supply. Therefore, the main problem lies in making sure to release these resources after usage. If they are not released then it will lead to resource leakage and may cause the system to either slow down or crash. It would be very helpful if users have a mechanism for the automatic setup and teardown of resources. In Python, it can be achieved by the usage of context managers which facilitate the proper handling of resources. The most common way of performing file operations is by using the keyword as shown below:

 # Python program showing a use of with keyword
 with open("test.txt") as f:  
     data = f.read()

When a file is opened, a file descriptor is consumed which is a limited resource. Only a certain number of files can be opened by a process at a time. The following program demonstrates it.

file_descriptors = []
for x in range(100000):
    file_descriptors.append(open('test.txt', 'w'))

it lead the error: OSError: [Errno 24] Too many open files: 'test.txt'

Python provides an easy way to manage resources: Context Managers. The with keyword is used. When it gets evaluated it should result in an object that performs context management. Context managers can be written using classes or functions(with decorators).

Creating a Context Manager: When creating context managers using classes, user need to ensure that the class has the methods: __enter__() and __exit__(). The __enter__() returns the resource that needs to be managed and the __exit__() does not return anything but performs the cleanup operations. First, let us create a simple class called ContextManager to understand the basic structure of creating context managers using classes, as shown below:

# Python program creating a context manager 
class ContextManager():
    def __init__(self):
        print('init method called')
         
    def __enter__(self):
        print('enter method called')
        return self
     
    def __exit__(self, exc_type, exc_value, exc_traceback):
        print('exit method called')
 
with ContextManager() as manager:
    print('with statement block')

Output:
init method called
enter method called
with statement block
exit method called

In this case, a ContextManager object is created. This is assigned to the variable after the keyword i.e manager. On running the above program, the following get executed in sequence:

  • __init__()
  • __enter__()
  • statement body (code inside the with block)
  • __exit__()[the parameters in this method are used to manage exceptions]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文