Как иметь несколько фиктивных файловых писателей в инструкции with?

Я прочитал в этот ответ из Возможно ли иметь необязательный оператор with/as в python? что у вас может быть фиктивный модуль записи файлов с contextmanager. Однако я хочу открыть несколько фиктивных модулей записи файлов в контексте оператора with.

Скажем, я создаю два фиктивных файла: touch a и touch b.

Учитывая первую часть скрипта:

#!/usr/bin/python

from contextlib import contextmanager

# File names
fa="a"
fb="b"

# Dummy file handler
none_context = contextmanager(lambda: iter([None]))()

Это дополнение работает с одним фиктивным модулем записи файлов (он печатает 2):

printing=False
with (open(fa) if printing else none_context) as writter:
    print 1 if printing else 2

Это также работает, потому что мы действительно читаем файлы (выводит 1):

printing=True
with (open(fa, "r") if printing else none_context) as writter, \
    (open(fb, "r") if printing else none_context) as another_writter:
    print 1 if printing else 2

Однако это не сработает, если мы используем два фиктивных средства записи файлов:

printing=False
with (open(fa, "r") if printing else none_context) as writter, \
    (open(fb, "r") if printing else none_context) as another_writter:
    print 1 if printing else 2

Он показывает ошибку:

Traceback (most recent call last):
  File "dummy_opener.py", line 23, in <module>
    with (open(fa, "r") if printing else none_context) as writter, \
  File "/usr/lib64/python2.7/contextlib.py", line 19, in __enter__
    raise RuntimeError("generator didn't yield")
RuntimeError: generator didn't yield

Почему это происходит? А также: как я могу заставить эти несколько команд with open работать с фиктивным средством записи файлов?


person fedorqui 'SO stop harming'    schedule 07.07.2015    source источник
comment
Пробовали ли вы более надежную версию из комментария (def none_context(a=None): return contextmanager(lambda: (x for x in [a]))())?   -  person jonrsharpe    schedule 07.07.2015
comment
@jonrsharpe работает, спасибо! Тем не менее, мне все еще интересно, почему мой подход не работает.   -  person fedorqui 'SO stop harming'    schedule 07.07.2015


Ответы (1)


Ваш код дает сбой, так как вы уже использовали итератор при первом вызове, если вы вызовете none_context() в блоке with, исходный код будет работать:

none_context = contextmanager(lambda: iter([None]))
printing=False

with open(fa, "r") if printing else none_context() as writter, \
    open(fb, "r") if printing else none_context() as another_writter:
    print 1 if printing else 2

Используя свой исходный код, вы можете видеть, что если вы добавите None для каждого открытия, код будет работать так, как ожидалось:

none_context = contextmanager(lambda: iter([None,None,None]))()
printing=False

with open(fa, "r") if printing else none_context as writter, \
    open(fb, "r") if printing else none_context as another_writter,\
    open(fb, "r") if printing else none_context as another_writer3:
    print 1 if printing else 2
person Padraic Cunningham    schedule 07.07.2015