📜  使用 @contextmanager 装饰器的上下文管理器

📅  最后修改于: 2022-05-13 01:55:20.616000             🧑  作者: Mango

使用 @contextmanager 装饰器的上下文管理器

装饰器是Python中非常强大和有用的工具,因为它允许程序员修改函数或类的行为。装饰器允许我们包装另一个函数以扩展被包装函数的行为,而无需永久修改它。

句法:

@decorator
def function(args):
    statements(s)

例子:

Python3
# Python program to demonstrate
# decorators
 
def msg_decorator(func):
     
    # Inner function
    def msg_wrapper(msg):
        print("A decorated line:", func(msg))
         
    return msg_wrapper
 
# Using the decorator
@msg_decorator
def print_name(name):
    return name
 
print_name("Pooventhiran")


Python3
# Python program to demonstrate
# Context Manager
 
with open('testfile.txt') as in_file:
    print(''.join(in_file.readlines()))


Python3
# 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')
   
# Driver code
with ContextManager() as manager:
    print('with statement block')


Python3
# Python program for creating a
# context manager using @contextmanager
# decorator
 
from contextlib import contextmanager
 
@contextmanager
def ContextManager():
     
    # Before yield as the enter method
    print("Enter method called")
    yield
     
    # After yield as the exit method
    print("Exit method called")
 
with ContextManager() as manager:
    print('with statement block')


输出:
A decorated line: Pooventhiran

在此示例中,每当调用 print_name() 时,首先会调用msg_decorator ,并将 print_name 作为参数。在 msg_decorator 内部,返回 msg_wrapper,它简单地调用传递给 msg_decorator 的任何函数,并使用传递给它的参数。虽然这个例子很简单,但这些在实际用例中非常强大,比如检查边界/特殊条件、预处理等。
注意:有关更多信息,请参阅Python中的装饰器。

上下文管理器

上下文管理器是 Python 的资源管理器。大多数情况下,我们使用文件作为资源(一种简单的资源)。我们通常不关心在执行结束时关闭文件。这是一种不好的编码习惯,当打开太多文件时,或者当程序因资源未正确释放而终止时,也会导致问题。上下文管理器通过自动管理资源来解决这个问题。在Python中,使用了 with 关键字。

例子:

Python3

# Python program to demonstrate
# Context Manager
 
with open('testfile.txt') as in_file:
    print(''.join(in_file.readlines()))

在上面显示的示例中,使用的文件由 ContextManager 自己管理,因为即使程序失败,它也会关闭文件。这个上下文管理器功能也可以内置到我们的程序中。用户需要确保该类具有方法:__enter__() 和 __exit__()。让我们看一个带有这些特殊方法的模板。

Python3

# 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')
   
# Driver code
with ContextManager() as manager:
    print('with statement block')
        

输出:

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

在上面的代码中,__enter__ 将在控件进入时执行 with 和 __exit__,当控件离开时执行 with 子句。我们可以在 contextlib.contextmanager 装饰器的帮助下简单地将任何函数作为上下文管理器,而无需编写单独的类或__enter__和 __exit__ 函数。

使用@contextmanager

我们必须使用 contextlib.contextmanager 来装饰一个生成器函数,它只产生一次。 yield 之前的所有内容都被认为是 __enter__ 部分,之后的所有内容都是 __exit__ 部分。生成器函数应该产生资源。

例子:让我们用这个装饰器重写上面的例子

Python3

# Python program for creating a
# context manager using @contextmanager
# decorator
 
from contextlib import contextmanager
 
@contextmanager
def ContextManager():
     
    # Before yield as the enter method
    print("Enter method called")
    yield
     
    # After yield as the exit method
    print("Exit method called")
 
with ContextManager() as manager:
    print('with statement block')

输出:

Enter method called
with statement block
Exit method called