2016-11-27 4 views
3

У меня возникают проблемы с информацией о печати, которая вводится из файла yaml с помощью PyYAML. Я пытаюсь уменьшить количество строк, не влияя на функциональность. В некоторых записях вывод должен быть добавлен к файлу, в других - к stdout.повторное открытие sys.stdout после его закрытия с помощью оператора

Сначала я использовал это несколько раз в моей функции ProcessData:

if logName: 
     fp = open(logName, 'a') 
    else: 
     fp = sys.stdout 
    print(........, file=fp) 
    print(........, file=fp) 
    if logName: 
     fp.close() 

Это работало, но имеет недостатки, не используя с заявления, когда что-то идет не так.

Реальная проблема заключается не в сложных операторах печати, но я

1) не хочет, чтобы дублировать код при печати в файл или sys.stdout
2) хочет использовать с заявление так, что файлы будут закрыты, если есть ошибки печати
3) существует несколько таких блоков, я не хочу, чтобы вызвать другую функцию для каждого из них, и таким образом предотвращая дублирование

кода Тогда я попытался это :

def processData(yamlData, logName=None): 
    ...... 
    with open(logName, 'a') if logName else sys.stdout as fp: 
     print(........, file=fp) 
     print(........, file=fp) 
    ..... 
    with open(logName, 'a') if logName else sys.stdout as fp: 
     print(........, file=fp) 
     print(........, file=fp) 

Если нет имени журнала, это приведет к ошибке «ValueError: операция ввода-вывода в закрытом файле». Любые предложения о том, как заставить это работать без оригинального дублирования? Можно ли повторно открыть sys.stdout?

+1

Вместо печати вы можете использовать регистратор. Это лучшая практика. –

+0

Спасибо, я посмотрю. Некоторые полезные пакеты, так мало времени ... – Brad

+0

@Brad Смотреть дальше! Введите _Python_, первый язык и стандартную библиотеку, где _ «должен быть один, а желательно, только один - единственный очевидный способ сделать это!» _ Если в стандартной библиотеке есть некоторые функциональные возможности, вы можете поспорить, что им было сложно сделать это типичный вариант использования. –

ответ

2

Вы можете «обернуть» sys.stdout в классе, чтобы предотвратить его закрытие в первую очередь.

with заявление вызывает __enter__ и __exit__ на экземпляры этого класса в начале и конце соответственно, так что просто убедитесь, что __exit__ ничего не делает:.

class StdOut: 
    def __enter__(self): 
     return sys.stdout 

    def __exit__(self, typ, val, trace): 
     pass 

stdout = StdOut() 

, а затем использовать stdout вместо sys.stdout

1

Буквальное вопрос - возобновление STDOUT

на самом низком уровне C, стандартный вывод - это хорошо известный file descriptor (целое число, указывающее на запись в таблице дескрипторов времени исполнения или системы), инициализированный в процессе после его создания. It cannot be reopened (with standard C means) once it's closed and must be duplicated beforehand if you still need it.

Одноразовый копия sys.stdout может быть создан так:

stdout_copy=os.fdopen(os.dup(sys.stdout.fileno()),sys.stdout.mode) 

(. В Python 3 os.fdopen() были объединены в open() и является псевдонимом к нему)

Вы можете вместо этого необходимо использовать sys.__stdout__, если sys.stdout был заменен.

Другой вопрос - обертывание функциональности в with логики

Прежде всего, рассмотрит стандартный способ для входа - а именно, logging модуля - чтобы не изобретать квадратное колесо. Открытие и закрытие файла по запросу вполне может быть реализовано с помощью его механизмов, и оно даже не требуется в подавляющем большинстве случаев.

Теперь единственный способ разрезать повторяющиеся части кода - обернуть повторяющуюся часть в подпрограмму (или блок кода, который обрабатывает список с элементами, описывающими, что он должен делать на каждой итерации, но он может только один раз). Есть три концептуальные части здесь, независимо от синтаксиса (это может быть try/finally точно так же как with):

  • оберточная построить
    • вкл. обработки
  • отверстие + код закрытия
  • обернутый код

исключение
  • Обертывание просто "открытие + закрытие кода" является самым простым, the other answer это один из возможных способов, но он оставляет повторяющиеся части with и print(........, file=fp).

  • Обернуть всю конструкцию сложнее, так как вам придется передать кусок кода в вашу потенциальную подпрограмму, а Python намеренно опускает анонимные блоки кода - вам нужно будет def, а затем сразу же использовать его, неловко.

    • декоратор или передача кода в качестве обратного вызова - это две возможности.
    • Если ваш код можно свести к шаблону (например, к набору сообщений), вы можете передать только этот шаблон и обработать его подпрограммой.