Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
274 views
in Technique[技术] by (71.8m points)

python - Class-based context manager vs generator-based one

There's an Indenter() class we could use to have text indentations levels like this:

    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__
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...