Использовать менеджер контекста для вывода скрипта Python в файл? - PullRequest
3 голосов
/ 14 декабря 2011

Я программирую скрипт, в котором у меня есть опция, которая будет передаваться в командной строке, должен ли скрипт печатать свои результаты в стандартный вывод или в предварительно определенный файл результатов. Схема кода для этого показана ниже. Теперь я немного прочитал о менеджерах контекста в Python, но не совсем уверен, стоит ли и как использовать менеджер контекста в этой конкретной ситуации. Поэтому я ищу совет

  1. имеет ли смысл использовать контекстный менеджер в этой задаче
  2. как это осуществить.

Итак, код без менеджера контекста:

option_file = True # would come from OptionParser in real code

if option_file:
    out = open("resultsfile", "w")
else:
    out = sys.stdout

# do some computations
out.write("Results of script")
# more computations and calls to out.write

if option_file:
    out.close()

1 Ответ

4 голосов
/ 14 декабря 2011

Менеджер контекста - это то, что вы можете использовать с оператором with. Он явно предназначен для:

  • выполнить настройку,
  • даст вам объект, а
  • снова выполнить какое-либо разложение (даже если вы подняли исключение).

Например, open может использоваться как менеджер контекста. В следующем коде

with open(...) as f:
    # do stuff

не имеет значения, что такое stuff, файл всегда будет закрыт. (Ну, обычно. За исключением глупых случаев, таких как отключение питания или остановка процесса.)

Вам следует использовать менеджер контекста, когда вы находитесь в такой ситуации. Это не выглядит так, как ты, поэтому я не вижу причин для менеджера контекста.


Существует альтернативный (не лучше и не хуже, просто другой) способ написания кода, использующий менеджер контекста. Если вы хотите временно перенаправить stdout - но убедитесь, что вы восстановили его, когда закончили - тогда вы находитесь в ситуации выше. Вот пример:

@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

Затем вы можете написать код, как

with open(...) as f:
    with redirect_stdout(f):
        # do stuff

и любые записи на стандартный вывод в stuff вместо этого перейдут на f.


РЕДАКТИРОВАТЬ: Вы правы, что нет никакого способа, чтобы иметь контекстный менеджер: либо вы в одном или нет. Вы всегда можете написать свой, который ничего не может сделать:

@contextlib.contextmanager
def maybe_open(path, do_nothing=True):
    if do_nothing:
        f = None
        yield sys.stdout
    else:
        f = open(path)
        yield f

    if f:
        f.close()

Это почти наверняка излишне.

...