Для чего предназначен оператор python «with»?

У вас есть #include <unistd.h>, где объявлено fork().

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

#define _XOPEN_SOURCE 600

Вы можете использовать 700, если считаете, что ваша система в основном совместима с POSIX 2008 или даже 500 для более старой системы. Поскольку fork() существует бесконечно, он будет отображаться с любым из них.

Если вы компилируете с -std=c99 --pedantic, то все объявления для POSIX будут скрыты, если вы явно не запросите их как показано .

Вы также можете играть с _POSIX_C_SOURCE, но с помощью _XOPEN_SOURCE подразумеваются правильные соответствующие _POSIX_C_SOURCE_POSIX_SOURCE и т. д.).

384
задан Wolf 14 November 2016 в 09:24
поделиться

8 ответов

  1. Я считаю, что на этот вопрос уже ответили другие пользователи до меня, поэтому я добавляю его только для полноты: оператор with упрощает обработку исключений, инкапсулируя общую подготовку и задачи очистки в так называемых менеджерах контекста . Более подробную информацию можно найти в PEP 343 . Например, оператор open сам по себе является диспетчером контекста, который позволяет вам открывать файл и держать его открытым, пока выполняется в контексте оператора with , в котором вы использовал его, и закройте его, как только вы покинете контекст, независимо от того, покинули ли вы его из-за исключения или во время обычного потока управления. Таким образом, оператор with может использоваться способами, аналогичными шаблону RAII в C ++: некоторый ресурс приобретается оператором with и освобождается, когда вы покидаете с контекстом .

  2. Некоторые примеры: открытие файлов с использованием с open (filename) как fp: , получение блокировок с использованием с блокировкой: (где lock является экземпляром threading.Lock ). Вы также можете создавать свои собственные контекстные менеджеры, используя декоратор contextmanager из contextlib .Например, я часто использую это, когда мне нужно временно изменить текущий каталог, а затем вернуться туда, где я был:

     from contextlib import contextmanager
    импорт ОС
    
    @contextmanager
    def working_directory (путь):
    current_dir = os.getcwd ()
    os.chdir (путь)
    пытаться:
    урожай
    наконец:
    os.chdir (current_dir)
    с рабочим_каталогом ("данные / материал"):
     # сделать что-нибудь с данными / вещами
    # вот я снова вернулся в исходный рабочий каталог
    

    Вот еще один пример, который временно перенаправляет sys.stdin , sys.stdout и sys.stderr на другой дескриптор файла и восстанавливает их позже:

     ] из contextlib import contextmanager
    import sys
    
    @contextmanager
    def перенаправлен (** kwds):
    stream_names = ["стандартный ввод", "стандартный вывод", "стандартный поток"]
    old_streams = {}
    пытаться:
    для sname в stream_names:
    stream = kwds.get (sname, Нет)
    если stream не равен None и stream! = getattr (sys, sname):
    old_streams [sname] = getattr (sys, sname)
    setattr (sys, sname, stream)
    урожай
    наконец:
    для sname поток в old_streams.iteritems ():
    setattr (sys, sname, stream)
    с перенаправлением (stdout = open ("/ tmp / log.txt", "w")):
     # эти операторы печати попадут в /tmp/log.txt
    распечатать "Тестовая запись 1"
    распечатать "Тестовая запись 2"
    # вернуться к обычному стандартному выводу
    print "Вернуться к нормальному стандартному выводу снова"
    

    И, наконец, еще один пример, который создает временную папку и очищает ее при выходе из контекста:

     from tempfile import mkdtemp
    из shutil import rmtree
    
    @contextmanager
    def временный_каталог (* аргументы, ** kwds):
    имя = mkdtemp (* аргументы, ** kwds)
    пытаться:
    название урожая
    наконец:
    шутил.rmtree (имя)
    с временным_dir () в качестве имени каталога:
     # делай что хочешь
    
376
ответ дан 22 November 2019 в 23:45
поделиться

Я бы посоветовал две интересные лекции:

  • PEP 343 The "with" Statement
  • Effbot Understanding Python's "with" statement

1. Оператор with используется для того, чтобы обернуть выполнение блока методами, определенными менеджером контекста. Это позволяет инкапсулировать общие шаблоны использования try...except...finally для удобного повторного использования.

2. Вы можете сделать что-то вроде:

with open("foo.txt") as foo_file:
    data = foo_file.read()

OR

from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
   do_something()

OR (Python 3.1)

with open('data') as input_file, open('result', 'w') as output_file:
   for line in input_file:
     output_file.write(parse(line))

OR

lock = threading.Lock()
with lock:
    # Critical section of code

3. Я не вижу здесь никакого антипаттерна.
Цитирую Погружение в Python:

try...finally - хорошо. with - лучше.

4. Полагаю, это связано с привычкой программистов использовать оператор try..catch..finally из других языков.

85
ответ дан 22 November 2019 в 23:45
поделиться

Оператор Python with является встроенной языковой поддержкой идиомы Resource Acquisition Is Initialization широко используемой в C++. Она предназначена для безопасного получения и освобождения ресурсов операционной системы.

Оператор with создает ресурсы внутри области видимости/блока. Вы пишете свой код, используя ресурсы внутри блока. При выходе из блока ресурсы освобождаются независимо от результатов работы кода в блоке (то есть, вышел ли блок нормально или из-за исключения).

Многие ресурсы в библиотеке Python подчиняются протоколу, требуемому оператором with, и поэтому могут использоваться с ним "из коробки". Однако любой может создать ресурсы, которые могут быть использованы в операторе with, реализуя хорошо документированный протокол: PEP 0343

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

37
ответ дан 22 November 2019 в 23:45
поделиться

Примером антипаттерна может быть использование с внутри цикла, когда было бы более эффективно иметь с вне цикла

например

for row in lines:
    with open("outfile","a") as f:
        f.write(row)

vs

with open("outfile","a") as f:
    for row in lines:
        f.write(row)

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

25
ответ дан 22 November 2019 в 23:45
поделиться

Опять же для полноты картины добавлю свой самый полезный случай использования with утверждений.

Я много занимаюсь научными вычислениями и для некоторых видов деятельности мне нужна библиотека Decimal для вычислений произвольной точности. В некоторых частях моего кода мне нужна высокая точность, а в большинстве других частей - меньшая.

Я устанавливаю точность по умолчанию на низкое число, а затем использую with, чтобы получить более точный ответ для некоторых секций:

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

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

25
ответ дан 22 November 2019 в 23:45
поделиться

пункты 1, 2 и 3 достаточно хорошо освещены:

4: он относительно новый, доступен только в python2.6 + (или python2.5 с использованием из __future__ import with_statement ])

4
ответ дан 22 November 2019 в 23:45
поделиться

Оператор with работает с так называемыми диспетчерами контекста:

http://docs.python.org /release/2.5.2/lib/typecontextmanager.html

Идея состоит в том, чтобы упростить обработку исключений, выполнив необходимую очистку после выхода из блока 'with'. Некоторые встроенные модули Python уже работают как менеджеры контекста.

3
ответ дан 22 November 2019 в 23:45
поделиться

См. PEP 343 - Оператор «with» , в конце есть пример раздела.

... новый оператор "with" в Python язык сделать можно исключить стандартные варианты использования операторов try / finally.

9
ответ дан 22 November 2019 в 23:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: