Что такое call/cc?

Вы открываете файл с режимом «a» вместо «w»?

См. Чтение и запись файлов в документах python

7.2. Чтение и запись файлов

open () возвращает объект файла и чаще всего используется с двумя аргументами: open (имя файла, режим).

>>> f = open('workfile', 'w')
>>> print f 

Первый аргумент - это строка, содержащая имя файла. Второй аргумент - это другая строка, содержащая несколько символов, описывающих способ использования файла. mode может быть «r», когда файл будет считан только «w» только для записи (существующий файл с тем же именем будет удален), а «a» открывает файл для добавления; любые данные, записанные в файл, автоматически добавляются в конец. 'r +' открывает файл для чтения и записи. Параметр mode не является обязательным; «r» будет приниматься, если он опущен.

В Windows, «b», добавленный в режим, открывает файл в двоичном режиме, поэтому существуют также такие режимы, как «rb», «wb» и «rb», г + Ь». Python в Windows делает различие между текстовыми и двоичными файлами; конечные символы в текстовых файлах автоматически изменяются, когда данные считываются или записываются. Эта за кадром модификация файловых данных отлично подходит для текстовых файлов ASCII, но это приведет к повреждению двоичных данных, подобных этим в файлах JPEG или EXE. Будьте очень осторожны, чтобы использовать двоичный режим при чтении и записи таких файлов. В Unix не помешает добавить «b» в режим, поэтому вы можете использовать его платформу независимо для всех двоичных файлов.

blockquote>

47
задан Michał Rudnicki 5 March 2009 в 09:34
поделиться

7 ответов

Посмотрите, я нашел этот Стиль Передачи Продолжения лучшее описание по этой теме.

Здесь лишен копии деталей той статьи:

Автор: Дата Marijn Haverbeke: 24-го июля 2007

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

function traverseDocument(node, func) {
  func(node);
  var children = node.childNodes;
  for (var i = 0; i < children.length; i++)
    traverseDocument(children[i], func);
}   

function capitaliseText(node) {
  if (node.nodeType == 3) // A text node
    node.nodeValue = node.nodeValue.toUpperCase();
}

traverseDocument(document.body, capitaliseText);

Это может быть преобразовано следующим образом: Мы добавляем дополнительный аргумент каждой функции, которая будет использоваться для передачи продолжения функции. Это продолжение является значением функции, представляющим действия, которые должны произойти после функции 'возвраты'. (Вызов) стек становится устаревшим в передающем продолжение стиле †• когда вызовы функции другая функция, которая является последней вещью, которую она делает. Вместо того, чтобы ожидать вызванной функции для возврата это помещает любую работу, которую это хочет сделать впоследствии в продолжение, которое это передает функции.

function traverseDocument(node, func, c) {
  var children = node.childNodes;
  function handleChildren(i, c) {
    if (i < children.length)
      traverseDocument(children[i], func,
                       function(){handleChildren(i + 1, c);});
    else
      c();
  }
  return func(node, function(){handleChildren(0, c);});
}

function capitaliseText(node, c) {
  if (node.nodeType == 3)
    node.nodeValue = node.nodeValue.toUpperCase();
  c();
}

traverseDocument(document.body, capitaliseText, function(){});

Предполагают, что у нас есть huuuuge документ для превращения в капитал. Просто пересечение его сразу занимает пять секунд, и замораживание браузера в течение пяти секунд является довольно плохим стилем. Рассмотрите эту простую модификацию capitaliseText (не обращайте внимание на ужасное глобальное):

var nodeCounter = 0;
function capitaliseText(node, c) {
  if (node.nodeType == 3)
    node.nodeValue = node.nodeValue.toUpperCase();

  nodeCounter++;
  if (nodeCounter % 20 == 0)
    setTimeout(c, 100);
  else
    c();
}

Теперь, каждые двадцать узлов, вычисление прервано, чтобы сто миллисекунд дали интерфейсу браузера момент для ответа на ввод данных пользователем. Очень примитивная форма поточной обработки †• можно даже выполнить множественные вычисления одновременно как это.

А чаще всего полезное приложение этого связано с XMLHttpRequests, или различный IFRAME и взломы ТЕГА SCRIPT раньше моделировали их. Они всегда требуют, чтобы работал с некоторым механизмом обратного вызова для обработки данных, которые передает обратно сервер. В простых случаях тривиальная функция сделает, или несколько globals могут использоваться для хранения состояния вычисления, которое должно быть возобновлено после того, как данные возвращаются. Со сложными случаями, например, когда данные используются функцией, которая должна возвратить некоторое значение его вызывающей стороне, продолжения значительно упрощают вещи. Вы просто регистрируете продолжение как обратный вызов, и Ваше вычисление возобновляется, когда запрос заканчивается.

16
ответ дан fredoverflow 7 November 2019 в 23:27
поделиться

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

(define x 0) ; dummy value - will be used to store continuation later

(+ 2 (call/cc (lambda (cc)
                (set! x cc)  ; set x to the continuation cc; namely, (+ 2 _)
                3)))         ; returns 5

(x 4) ; returns 6

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

(* 123 (+ 345 (* 789 (x 5)))) ; returns 7

  reason: it is because (x 5) replaces the existing continuation,
          (* 123 (+ 345 (* 789 _))), with x, (+ 2 _), and returns
          5 to x, creating (+ 2 5), or 7.

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

22
ответ дан Community 7 November 2019 в 23:27
поделиться

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

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

Другой способ использовать продолжение был бы к [1 121], думают о вызовах метода замены с несколькими нитевидными объектами , которые сосуществуют параллельно (или выполнение или приостановленный) передача управления друг другу использующему контексты продолжения вместо 'классика' call парадигма. Они воздействовали бы на глобальные (общие) данные вместо того, чтобы полагаться на параметры. Это в некоторой степени более гибко, чем call в том смысле, что стек не должен заканчиваться тогда вниз (calls, , вложил ), но управление может раздать произвольно.

Попытка визуализировать это понятие на языке такой C, предположите иметь один большой цикл с синглом switch(continuation_point) { case point1: ... } оператор, где каждый case соответствует точке сохранения продолжения, и где код в каждом case может изменить значение continuation_point и оставить управление тому continuation_point break луг от switch и привлечение следующего повторения в цикле.

, Каков контекст Вашего вопроса? Какие-либо конкретные сценарии Вы интересуетесь? Какой-либо конкретный язык программирования? Пример потока/волокна выше достаточного?

9
ответ дан Tim Cooper 7 November 2019 в 23:27
поделиться

Лучшее объяснение, которое я видел, находится в книге Paul Graham, На Lisp.

3
ответ дан Jacob Gabrielson 7 November 2019 в 23:27
поделиться

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

Прежде, чем перейти к коду функции Вы сохраняете некоторое состояние на стеке (т.е. Вы продвигаете свой обратный адрес, и стек уже содержит Ваших местных жителей). Это - по существу продолжение. Когда функция закончилась, она должна определить, куда отправить поток выполнения. Это использует продолжение, сохраненное на стеке, выталкивая обратный адрес и переходя к нему.

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

РЕДАКТИРОВАНИЕ на основе комментария:

продолжение является полным режимом выполнения. В любой точке выполнения можно разделить программу на две части (вовремя, не расположить с интервалами) - то, что работало к этой точке и всему, что это собирается выполнить отсюда. "Текущее продолжение" является "всем, что это собирается выполнить отсюда" (можно думать о нем отчасти как функция, которая сделает все, что остальная часть программы сделала бы). Так функция Вы предоставляете к call/cc, передается продолжение, которое было текущим, когда call/cc был вызван. Функция может использовать продолжение для возврата выполнения call/cc оператор (более вероятно, хотя это раздаст продолжение к чему-то еще, потому что, если это использовало его непосредственно, это могло бы сделать простой возврат вместо этого).

5
ответ дан Dave 7 November 2019 в 23:27
поделиться

Существует несколько уровней к пониманию call/cc. Сначала необходимо понять условия и, как механизм работает. Тогда понимание того, как и то, когда call/cc используется в "реальном" программировании, необходимо.

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

Для второго уровня я рекомендую следующему классику Friedman.

Daniel P. Friedman. "Приложения Продолжений: Приглашенное Учебное руководство". 1 988 Принципов Языков программирования (POPL88). Январь 1988.

2
ответ дан soegaard 7 November 2019 в 23:27
поделиться

Когда я пытался понять call / cc, я обнаружил, что эта страница call-with-current-continue-for-C-программистов оказалась полезной.

4
ответ дан 26 November 2019 в 18:55
поделиться
Другие вопросы по тегам:

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