代码之家  ›  专栏  ›  技术社区  ›  Mehrdad Pedramfar

生成器和上下文管理器同时

  •  0
  • Mehrdad Pedramfar  · 技术社区  · 6 年前

    假设我有一些代码要运行:

    with F() as o:
        while True:
            a = o.send(2)
            print(a)
    

    这意味着 F 类应返回 generator 而且它也是 context manager ,通常我也希望上下文管理器是生成器。

    我试过这个:

    class F:
    
        def __enter__(self):
            return self
    
        def __exit__(self, *exc):
            print('exit')
    
        def __next__(self):
            return 5
    
        def __iter__(self):
            return self
    

    如预期,这将返回 AttributeError: 'F' object has no attribute 'send' ,我通过添加以下内容来处理此错误:

    def send(self, param):
        self.__next__()
    

    但我认为这不是一个好的方法,我环顾四周,发现 this ,但他们没有使用 send 如我所愿,我需要那个实例是一个生成器。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Andrej Kesely    6 年前

    你可以用 collections.abc 并将你的类划分为子类 F Generator ( manual pages )如果你实施 进入 出口 ,您的实例将是生成器,并且还具有上下文管理器支持:

    from collections.abc import Generator
    
    class F(Generator):
        def __init__(self):
            self.__my_generator = self._my_generator()
            next(self.__my_generator)   # prime the generator
    
        def _my_generator(self):
            while True:
                v = yield 42
                print('generator received ', v)
    
        # context manager interace:
        def __enter__(self):
            return self
    
        def __exit__(self, *exc):
            print('exit')
    
        # Generator interface:
        def send(self, value):
            return self.__my_generator.send(value)
    
        def throw(self, typ, value=None, traceback=None):
            return self.__my_generator.throw(typ, value, traceback)
    
    
    with F() as o:
        while True:
            a = o.send(2)
            print('I received ', a)
    

    印刷品:

    generator received  2
    I received  42
    ...etc.