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

标签 python python-decorators contextmanager

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

这就是我想要做的:

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 确保调用清理函数。

所以有两个问题:

  1. 我如何在装饰器中使用上下文管理器,据我所知装饰器必须返回一个函数,但如果我返回函数(如上面的代码),上下文管理器将如何调用清理?

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

最佳答案

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

How do I use a context manager inside a decorator?

就像您在其他任何地方使用上下文管理器一样。考虑这个程序,它使用装饰器在调用函数时透明地将 str 转换为 file:

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

如您所见,装饰函数在装饰函数的调用周围使用上下文管理器。

How do I pass an object created in decorator to the decorated function, if I pass it like in above code, how would I call the decorated function?

就像将对象传递给任何函数一样。请参阅上面的示例。装饰器创建一个 file 对象并将其传递给装饰函数。


为了完整起见,这里是您的示例程序并修复了错误:

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

关于python - 如何在装饰器中使用上下文管理器以及如何将在装饰器中创建的对象传递给装饰函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30339334/

相关文章:

python - python 将包含日期时间对象的记录插入 mysql 数据库时出现问题

python flask API模块如何将动态参数传递给装饰器

使用 line_profiler 进行 Python 分析 - 即时删除 @profile 语句的巧妙方法?

python - 如何在 Python 中将变量放在堆栈/上下文中

Python MySQL TypeError : must be str, 不是元组

python - 语法错误 "no viable alternative at input ' self '”

python - python中最小/最大函数中的参数数量错误

Python,装饰函数中引用类实例/方法

Python MySQL 和上下文管理器 : __exit__ Attribute error

python - 在 contextlib.contextmanager 中产生