Python 如何在装饰器中使用上下文管理器,以及如何将在装饰器中创建的对象传递给装饰函数

Python 如何在装饰器中使用上下文管理器,以及如何将在装饰器中创建的对象传递给装饰函数,python,python-decorators,contextmanager,Python,Python Decorators,Contextmanager,我有一个测试类,需要在最后做一些清理。为了确保用户不会忘记这样做,我想在类中添加一个上下文管理器。我还有一个装饰器,在里面我想使用这个上下文管理器创建一个测试类的对象,并将其传递给装饰函数。有可能吗 这就是我想要做的: class test: def __init__(self, name): self._name = name print "my name is {0}".format(name) def exit(): pri

我有一个测试类,需要在最后做一些清理。为了确保用户不会忘记这样做,我想在类中添加一个上下文管理器。我还有一个装饰器,在里面我想使用这个上下文管理器创建一个测试类的对象,并将其传递给装饰函数。有可能吗

这就是我想要做的:

class test:
    def __init__(self, name):
        self._name = name
        print "my name is {0}".format(name)

    def exit():
        print "exiting"

    @contextmanager
    def testcm(self):
        print "inside cm"
        try:
            yield self
        finally:
            self.exit()

    def randomtest(self, str):
        print "Inside random test {0}".format(str)


def decorate(name):
    def wrapper(testf):
        def testf_wrapper(test):
            with test(name).testcm() as testobj:
                return testf(testobj)
            return testf_wrapper
        return wrapper
    return decorate

@decorate("whatever")
def testf(testobj):
    testobj.randomtest("randomness")
函数
testf
获取测试类对象-
testobj
,并对其进行处理。之后,由于使用了上下文管理器,
testcm
确保调用了cleanup函数

因此有两个问题:

  • 如何在装饰器中使用上下文管理器,据我所知,装饰器必须返回函数,但如果我返回函数(如上面的代码所示),上下文管理器将如何调用cleanup

  • 我如何将在decorator中创建的对象传递给修饰函数,如果我像上面的代码那样传递它,我将如何调用修饰函数


  • 您的示例程序中有几个错误,我在所有的
    test
    /
    testf
    /
    testobj
    冗余中迷失了方向。请允许我直接回答你的问题

    如何在装饰器中使用上下文管理器

    正如您在其他任何地方使用上下文管理器一样。考虑这个程序,在调用函数:

    时,使用装饰器透明地将<代码> STR >转换为<代码>文件>代码>。
    def opener(func):
        def wrapper(name):
            with open(name) as input_file:
                func(input_file)
        return wrapper
    
    @opener
    def first_line(fd):
        print fd.readline()
    
    first_line('/etc/passwd')
    
    如您所见,decorator函数在调用修饰函数时使用上下文管理器

    我如何将在decorator中创建的对象传递给修饰函数,如果我像上面的代码那样传递它,我将如何调用修饰函数

    正如您将对象传递给任何函数一样。见我上面的例子。装饰器创建一个
    文件
    对象,并将其传递给装饰函数


    为完整起见,以下是您的示例程序,错误已修复:

    from contextlib import contextmanager
    
    class test:
        def __init__(self, name):
            self._name = name
            print "my name is {0}".format(name)
    
        def exit(self):
            print "exiting"
    
        @contextmanager
        def testcm(self):
            print "inside cm"
            try:
                yield self
            finally:
                self.exit()
    
        def randomtest(self, str):
            print "Inside random test {0}".format(str)
    
    
    def decorate(name):
        def wrapper(testf):
            def testf_wrapper():
                with test(name).testcm() as testobj:
                    return testf(testobj)
            return testf_wrapper
        return wrapper
    
    @decorate("whatever")
    def testf(testobj):
        testobj.randomtest("randomness")
    
    
    testf()