Python中的上下文管理器和装饰器之间的区别

时间:2018-06-12 18:21:08

标签: python python-decorators contextmanager

两者之间的主要区别是什么?我一直在研究Python并遇到过它们。装饰器本质上是一个包装另一个函数的函数,你可以在特定函数执行之前和之后做任何事情。

def my_decorator(some_function):
    def wrapper(*args, **kwargs):
        print("Do something before the function is called")
        some_function(*args, **kwargs)
        print("Do something after the function is called")

    return wrapper

@my_decorator
def addition(a, b):
    result = a+b
    print("Addition of {} and {} is {}".format(a,b,result))

但是在研究了Context Manager之后,我不禁注意到它也有一个输入退出,你可以在那里做大部分类似的操作。

from contextlib import contextmanager

@contextmanager
def open_file(path, mode):
    the_file = open(path, mode)
    yield the_file
    the_file.close()

files = []

for x in range(100000):
    with open_file('foo.txt', 'w') as infile:
        files.append(infile)

for f in files:
    if not f.closed:
        print('not closed')

屈服之前的所有东西都被视为“输入”的一部分以及“退出”的一部分之后的所有内容。

虽然上下文管理器和装饰器在语法上都不同,但它们的行为可以看作是相似的。那么区别是什么呢?当人们应该使用其中任何一种时,有哪些不同的场景?

2 个答案:

答案 0 :(得分:8)

它们是完全独立的概念,不应该以同样的方式看待它们。

装饰器允许您在定义函数或类时扩充或替换。这比在函数调用之前或之后执行事务要广泛得多。当然,您的特定装饰器允许您在函数调用之前和之后执行某些操作,未提供异常,或者您显式处理异常。但您也可以使用装饰器向函数对象添加属性,或更新某种注册表。或者返回完全不同的东西并忽略原始功能。或者生成一个包装器来操作传入的参数,或者原始函数的返回值。上下文管理员不能做任何这些事情。

另一方面,上下文管理器可以让你抽象出try: ... finally: constructs,在中无论块如何退出,你都可以在块的末尾执行更多的代码。即使块引发异常,或者使用return退出函数,仍然会调用上下文管理器__exit__方法,无论。上下文管理器甚至可以抑制块中引发的任何异常。

这两个概念完全不相关。当您需要对函数或类进行某些操作时,请使用装饰器。如果要在块结束后清理或执行其他操作,请使用上下文管理器。

答案 1 :(得分:0)

它们是完全不同的概念。

上下文管理器是与python with关键字一起使用的对象。它在进入块并退出块时运行代码。

装饰器是对函数或类定义的修改。它运行的代码替换了正在定义的函数。

@D
def Y(...):
    ...

只是另一种写作方式

def Y(...):
    ....
Y = D(Y)