我们可以将ContextManager Decorator与__Enter __()和__EXIT __()方法混合使用,而__()方法与语句中的另一个类中的其他类中的方法相混合?

发布于 2025-01-23 02:32:41 字数 1677 浏览 3 评论 0原文

在python3.8中,我非常熟悉传统__输入____退出__魔术方法,但@coce>@contextlib.contlib.contextmanager decorator。是否可以将单个中的两个模式与语句混合在一起?

以下(高度人为)脚本应该更清楚地解释问题。 contextClass.enter_context_function()contextClass.exit_context_function()是否有定义仅使用context_function()函数并使单元测试通过?还是这些模式是互斥的?

import contextlib


NUMBERS = []


@contextlib.contextmanager
def context_function():
    NUMBERS.append(3)
    try:
        yield
    finally:
        NUMBERS.append(5)


class ContextClass:
    def __init__(self):
        self.numbers = NUMBERS
        self.numbers.append(1)

    def __enter__(self):
        self.numbers.append(2)
        self.enter_context_function() # should append 3
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.exit_context_function() # should append 5
        self.numbers.append(6)

    def function_call(self):
        self.numbers.append(4)

    def enter_context_function(self):
        # FIX ME!
        pass

    def exit_context_function(self):
        # FIX ME!
        pass


if __name__ == "__main__":
    import unittest

    class TestContextManagerFunctionAndClass(unittest.TestCase):
        def test_context_function_and_class(self):
            with ContextClass() as cc:
                cc.function_call()
            self.assertEqual(NUMBERS, [1, 2, 3, 4, 5, 6])

    unittest.main()

我知道有更好的方法可以解决一个类似的问题(特别是重写context_function作为具有其自己_____ ____ exit> __ exit __方法的类,但是我M试图更好地了解上下文Manager Decorator的工作方式。

In python3.8 I'm very familiar with the traditional __enter__ and __exit__ magic methods but new to the @contextlib.contextmanager decorator. Is it possible to mix the two patterns inside a single with statement?

The following (highly contrived) script should explain the problem more clearly. Is there a definition of ContextClass.enter_context_function() and ContextClass.exit_context_function() (I imagine something needs to change inside __init__ as well) that only use the context_function() function and makes the unit tests pass? Or are these patterns mutually exclusive?

import contextlib


NUMBERS = []


@contextlib.contextmanager
def context_function():
    NUMBERS.append(3)
    try:
        yield
    finally:
        NUMBERS.append(5)


class ContextClass:
    def __init__(self):
        self.numbers = NUMBERS
        self.numbers.append(1)

    def __enter__(self):
        self.numbers.append(2)
        self.enter_context_function() # should append 3
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.exit_context_function() # should append 5
        self.numbers.append(6)

    def function_call(self):
        self.numbers.append(4)

    def enter_context_function(self):
        # FIX ME!
        pass

    def exit_context_function(self):
        # FIX ME!
        pass


if __name__ == "__main__":
    import unittest

    class TestContextManagerFunctionAndClass(unittest.TestCase):
        def test_context_function_and_class(self):
            with ContextClass() as cc:
                cc.function_call()
            self.assertEqual(NUMBERS, [1, 2, 3, 4, 5, 6])

    unittest.main()

I understand there are better ways to solve a similar problem (specifically rewriting context_function as a class with its own __enter__ and __exit__ methods, but I'm trying to better understand exactly how the contextmanager decorator works.

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

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

发布评论

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

评论(1

薄荷→糖丶微凉 2025-01-30 02:32:41

__ Init __无需更改。 “使单位测试通过”的手册方式是:

def enter_context_function(self):
    self._context_mgr = context_function()
    self._context_mgr.__enter__()

def exit_context_function(self):
    self._context_mgr.__exit__(None, None, None)

但是,有点缺少上下文管理者的点。它们旨在在a

另请注意,如书面,如果加剧后代码,则无法达到 line(5) line(“拆卸”)。应该像这样写:

@contextlib.contextmanager
def context_function():
    NUMBERS.append(3)
    try:
        yield
    finally:
        NUMBERS.append(5)

No change in the __init__ is necessary. The manual way which "makes the unit tests pass" would be:

def enter_context_function(self):
    self._context_mgr = context_function()
    self._context_mgr.__enter__()

def exit_context_function(self):
    self._context_mgr.__exit__(None, None, None)

However, it's kind of missing the point of context-managers. They're intended to be used in a with-statement.

Also note that, as written, the NUMBERS.append(5) line (the "teardown") may not be reached if the code after yielding raises. It should be written like this:

@contextlib.contextmanager
def context_function():
    NUMBERS.append(3)
    try:
        yield
    finally:
        NUMBERS.append(5)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文