简体   繁体   English

基于类的上下文管理器与基于生成器的上下文管理器

[英]Class-based context manager vs generator-based one

There's an Indenter() class we could use to have text indentations levels like this:有一个Indenter()类,我们可以使用这样的文本缩进级别:

    hi!
        hello
            bonjour

The class-based implementation of the context manager is:上下文管理器的基于类的实现是:

class Indenter:
    def __init__(self):
        self.level = 0

    def __enter__(self):
        self.level += 1
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.level -= 1

    def print(self, text):
        print('    ' * self.level + text)


with Indenter() as indent:
    indent.print('hi')
    with indent:
        indent.print('hello!')
        with indent:
            indent.print('bonjour')

I wonder if it is possible to implement the same solution in the generator-based context manager?我想知道是否可以在基于生成器的上下文管理器中实现相同的解决方案? The solutions I tried did not work, probably because I just did not grasp the idea of context managers...我尝试的解决方案不起作用,可能是因为我没有掌握上下文管理器的想法......

UPDATE: Here's my approach with printing function onboard, so the context yields this function.更新:这是我使用板载打印功能的方法,因此上下文会产生此功能。 It is better, but still works only with single indentation:它更好,但仍仅适用于单个缩进:

from contextlib import contextmanager

@contextmanager
def indenter():
    level = 0
    def prints(text):
        print('____' * level + text)
    try:
        level += 1
        yield prints
    finally:
        level -= 1

with indenter() as ind:
    ind('aaaa')
    with ind:
        ind('bbbbb')

____aaaa
---------------------------------------------------------------------------
AttributeError     Traceback (most recent call last)
     29 with indenter() as ind:
     30     ind('aaaa')
---> 31     with ind:
     32         ind('bbbbb')

AttributeError: __enter__

I came up with this.我想出了这个。 It can be used in a similar way as your class version (but not exactly the same).它可以以与您的类版本类似的方式使用(但不完全相同)。

from contextlib import contextmanager

def indenter():
    level = 0

    def prints(text):
        print('____' * level + text)

    @contextmanager
    def ind():
        nonlocal level
        try:
            level += 1
            yield prints
        finally:
            level -= 1
    return ind


ind = indenter()
with ind() as prints:
    prints('aaa')
    with ind() as prints:
        prints('bbb')
        with ind() as prints:
            prints('ccc')

Output:输出:

____aaa
________bbb
____________ccc

Ok, this works for me: 好的,这对我有用:

from contextlib import contextmanager

@contextmanager
def indenter(level=0):
    def prints(text):
        print('____' * level + text)
    try:
        level += 1
        yield prints
    finally:
        level -= 1


with indenter() as ind:
    print('0000')
    ind('1111')
    with indenter(1) as ind:
        ind('2222')

Output: 输出:

0000
____1111
________2222

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM