Похоже, что это связано с несколькими другими вопросами, которые были заданы (например, с этим ), но я не могу понять, как сделать именно то, что я хочу. Возможно, функции замены - это неправильный инструмент для работы, что также будет вполне приемлемым ответом. Я гораздо лучше знаком с Python, чем с R, и я легко могу понять, как я хочу это сделать в Python, но я не могу понять, как подойти к нему в R.
Проблема: Я пытаюсь изменить объект на месте внутри функции, не возвращая его, но мне не нужно для передачи значения, которое его изменяет, потому что это значение является результатом вызова функции, который уже содержится в объекте.
Более конкретно, у меня есть список (технически это класс s3, но я не думаю, что это действительно имеет отношение к этой проблеме), что содержит некоторые вещи, относящиеся к процессу, запущенному с помощью processx::process$new()
call. Для воспроизводимости вот скрипт игрушечной оболочки, который вы можете запустить, и код для получения моего res
объекта:
echo '
echo $1
sleep 1s
echo "naw 1"
sleep 1s
echo "naw 2"
sleep 1s
echo "naw 3"
sleep 1s
echo "naw 4"
sleep 1s
echo "naw 5"
echo "All done."
' > naw.sh
Тогда моя оболочка выглядит примерно так:
run_sh <- function(.args, ...) {
p <- processx::process$new("sh", .args, ..., stdout = "|", stderr = "2>&1")
return(list(process = p, orig_args = .args, output = NULL))
}
res <- run_sh(c("naw.sh", "hello"))
И res
должно выглядеть как
$process
PROCESS 'sh', running, pid 19882.
$output
NULL
$orig_args
[1] "naw.sh" "hello"
Итак, специфическая проблема c здесь немного присуща process$new
, но я думаю, что общий принцип важен. Я пытаюсь собрать все выходные данные этого процесса после его завершения, но вы можете вызвать process$new$read_all_output_lines()
(или его родственные функции) только один раз, потому что в первый раз он вернет результат из буфера, а в последующие раз он ничего не вернет. , Кроме того, я собираюсь вызвать их несколько, а затем вернуться, чтобы «проверить их», поэтому я не могу просто сразу вызвать res$process$read_all_output_lines()
, потому что тогда он будет ждать окончания процесса до sh, прежде чем функция вернется. , что не , что я хочу.
Поэтому я пытаюсь сохранить результат этого вызова в res$output
, а затем просто сохранить его и вернуть его при последующих вызовах. Оооочень ... Мне нужно иметь функцию для изменения res
вместо с помощью res$output <- res$process$read_all_output_lines()
.
Вот что я пробовал, основываясь на указаниях типа this, но это не сработало.
get_output <- function(.res) {
# check if process is still alive (as of now, can only get output from finished process)
if (.res$process$is_alive()) {
warning(paste0("Process ", .res$process$get_pid(), " is still running. You cannot read the output until it is finished."))
invisible()
} else {
# if output has not been read from buffer, read it
if (is.null(.res$output)) {
output <- .res$process$read_all_output_lines()
update_output(.res) <- output
}
# return output
return(.res$output)
}
}
`update_output<-` <- function(.res, ..., value) {
.res$output <- value
.res
}
Вызов get_output(res)
работает в первый раз, но не сохраняет выходные данные в res$output
для последующего доступа, поэтому последующие вызовы ничего не возвращают.
Я также пробовал что-то вроде этого:
`get_output2<-` <- function(.res, value) {
# check if process is still alive (as of now, can only get output from finished process)
if (.res$process$is_alive()) {
warning(paste0("Process ", .res$process$get_pid(), " is still running. You cannot read the output until it is finished."))
.res
} else {
# if output has not been read from buffer, read it
if (is.null(.res$output)) {
output <- .res$process$read_all_output_lines()
update_output(.res) <- output
}
# return output
print(value)
.res
}
}
, который просто выбрасывает value
, но это глупо, потому что вы должны вызывать его с назначением типа get_output(res) <- "fake"
который я ненавижу.
Очевидно, я мог бы также просто вернуть измененный объект res
, но мне это не нравится, потому что тогда пользователь должен знать, чтобы сделать res <- get_output(res)
, и если они забудут это сделать (первый раз), затем выход теряется для эфира и никогда не может быть восстановлен. Не хорошо.
Любая помощь очень ценится!