сценарій розриву / виходу


85

У мене є програма, яка виконує певний аналіз даних і має кілька сотень рядків.

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

Я спробував break, browserі quitжоден з них не зупинити виконання решти програми (і quitзупиняє виконання, а також повністю кинути палити R, який не те , що я хочу , щоб це відбулося). Моя остання інстанція - це створення if-elseзаяви, як показано нижче:

 if(n < 500){}
 else{*insert rest of program here*}

але це здається поганою практикою кодування. Мені чогось не вистачає?


4
quitнайімовірніше зупиняє виконання решти програми. Будь ласка, надайте відтворюваний приклад .
Джошуа Ульріх

@JakeBurkhead - чи є мій код вище (з порожнім оператором if) найкращим способом піти? @Joshua Ulrich, quitвиходить з усієї R, але я хочу повернутися до консолі R, оскільки програма повинна залишатися відкритою для моїх цілей.
user2588829

Що ви маєте на увазі під програмою? Ви маєте на увазі, що у вас є функція, яку ви написали, або ви використовуєте сценарій?
Gavin Simpson

if-else - це, мабуть, правильний спосіб вирішити це. Винятки становлять ситуації, які не повинні відбуватися, якщо все використовується правильно. Якщо щось може статися, і ви знаєте, як з цим боротися, використовуйте нормальний потік управління.
Matthew

Відповіді:


59

Ви можете використовувати stopifnot()функцію, якщо хочете, щоб програма видала помилку:

foo <- function(x) {
    stopifnot(x > 500)
    # rest of program
}

+1! Думаю, функцію fooслід називати початком сценарію та містити інші
елементи

22
stopifnotзручно, але if(x < 500) { stop("Not enough observations in 'x': n < 500")}кращою є сформована відповідь . Крім того, якщо це щось для пакетного завдання, корисно вирішити проблему без помилок.
Gavin Simpson

4
Припиніть намагатися заплутати OP. Що він хоче, це кинути () або зупинити (), а не stopifnot ().
stackoverflowuser2010

10
@ Stackoverflowuser2010 Він не хоче quit(див питання!) Я навіть не думаю , що stopв stopifnotце кращий спосіб впоратися з цим; stopвидає помилку, весь сценарій просто перерветься. Хоча stopifnot(або stop), здається, найбільше сподобався ОП, відповідь на написання функції чистого виходу, без помилок, є вигіднішою в широкому діапазоні ситуацій. Написавши багато тривалих сценаріїв для великих завдань аналізу даних, ніщо не дратує більше, ніж функції, які видають помилки замість того, щоб вирішити проблему і повернутися чисто. Але явно не знаю, про що я ...
Гевін Сімпсон

Чи можете ви пояснити свій коментар щодо виникнення помилки @GavinSimpson? Коли я намагаюся, stop("my message")мене друкують у терміналі Error: "my message" Execution halted. Отже, це показує вихідне повідомлення про помилку, але чи ви хочете сказати, що воно не "видає" помилку? (тобто це не зупинить пакетне завдання, для якого було встановлено перерву, якщо будь-який із скриптів, які він викликає, видає помилки). Дякую! (Зараз я називаю сценарій за допомогою Rscript)
rrr

13

Не гарно, але ось спосіб реалізувати exit()команду на R, яка працює для мене.

exit <- function() {
  .Internal(.invokeRestart(list(NULL, NULL), NULL))
}

print("this is the last message")
exit()
print("you should not see this")

Тільки злегка перевірено, але коли я запускаю це, я бачу, this is the last messageі тоді сценарій переривається без жодного повідомлення про помилку.


Недоліком є ​​те, що це заборонено для коду в пакеті CRAN. Отже, якщо ви маєте намір використовувати вас у пакеті, який ви хочете завантажити в CRAN, це видасть попередження в R CMD CHECK.
MS Berends

1
Так, це більше схоже на системну функцію. Це може зламатись, якщо змінити внутрішні деталі інтерпретатора, тож, можливо, це краще частина ядра R, а не в окремій упаковці? Я знайшов це, дотримуючись різних шляхів через вихідний код R, щоб побачити, як я міг опинитися в правильному місці, щоб вийти з інтерпретатора без повідомлення про помилку. Я знайшов не так вже й багато способів туди дістатися; ось чому я використовую, .invokeRestartщо, в свою чергу, здається, потребує .Internal.
jochen

О так, крім політики CRAN, я вважаю, що це гарне рішення! Дозвольте мені доставити вам +10 представників;)
MS Berends

дивний. Я щойно спробував це, і останній рядок виводу був [1] "ви не повинні бачити цього" R версія 3.4.3 (2017-11-30) Платформа: x86_64-pc-linux-gnu (64-розрядна версія) Запуск: Red Hat Enterprise Linux Server, випуск 6.10 (Сантьяго)
CodingMatters,

@aspiringGuru Я щойно спробував, і це все ще працює для мене. Ви запускали команди як сценарій? Якщо ви запускаєте їх один за одним у командному рядку ( наприклад, за допомогою копіювання та вставки), то, звичайно, exit()не можна перешкодити виконанню наступної команди (яка ще не введена) ...
jochen

12

Змініть свою конструкцію if-else:

if(n >= 500) {
  # do stuff
}
# no need for else

2
досить просто, і я думаю, це може бути найкращим, що я можу зробити, дякую
user2588829

9

Редагувати: Здається, OP виконує довгий скрипт, у цьому випадку потрібно лише обернути частину сценарію після контролю якості за допомогою

if (n >= 500) {

.... long running code here

}

Якщо вирваєтеся з функції , ви, мабуть, просто захочете return(), явно або неявно.

Наприклад, явне подвійне повернення

foo <- function(x) {
  if(x < 10) {
    return(NA)
  } else {
    xx <- seq_len(x)
    xx <- cumsum(xx)
  }
  xx ## return(xx) is implied here
}

> foo(5)
[1] 0
> foo(10)
 [1]  1  3  6 10 15 21 28 36 45 55

Маючи return()на увазі, я маю на увазі, що останній рядок - це як би ви зробили return(xx), але трохи ефективніше залишити дзвінок return().

Деякі вважають використання кількох повернень поганим стилем; у довгих функціях відстеження місця виходу функції може ускладнитися або спричинити помилки. Отже, альтернативою є наявність єдиної точки повернення, але зміна об’єкта повернення за допомогою if () else ()речення. Така модифікація foo()була б

foo <- function(x) {
  ## out is NA or cumsum(xx) depending on x
  out <- if(x < 10) {
    NA
  } else {
    xx <- seq_len(x)
    cumsum(xx)
  }
  out ## return(out) is implied here
}

> foo(5)
[1] NA
> foo(10)
 [1]  1  3  6 10 15 21 28 36 45 55

Я теж про це думав, але незрозуміло, що OP говорить про вихід із функції.
Томас

Так, Томас має рацію - я не кажу про вирвання з функції.
user2588829

1
@ user2588829 Вам було б набагато краще поставити це як функцію в R, а не як сценарій 100+ рядків.
Gavin Simpson

@GavinSimpson о, я все ще новачок у R, тому я цього не знав. Якщо я визначу її як функцію 100+ рядків, це краща практика?
user2588829

1
@ user2588829 Так, набагато краще. Ви керуєте аргументами функції, щоб передати те, що потрібно. Крім того, замість отримання понад 100 рядків коду для запуску аналізу, який ви просто робите myFun(arg1, arg2, arg3)тощо. Це просто набагато кращий спосіб організації речей.
Gavin Simpson

9

Можливо, ви просто захочете в якийсь момент припинити виконувати довгий сценарій. тобто як ви хочете жорстко закодувати вихід () на C або Python.

print("this is the last message")
stop()
print("you should not see this")

1
Для цього коду я отримую повідомлення про помилку Error in eval(expr, envir, enclos) :.
jochen

2
Так, страта дійсно зупиняється. Випадково, якщо замінити stop()на exit()або please.stop.now(), сценарій також зупиняється (звичайно, різні повідомлення про помилки відрізняються).
jochen

1
@jochen Додавання цитованої фрази всередині stop()команди може допомогти відрізнити цю "помилку" від інших повідомлень. Наприклад: stop("Manual break inserted here")може бути більш інформативним, ніж stop()поодинці.
Омар Васов

3

Це давнє запитання, але поки немає чистого рішення. Це, мабуть, не відповідає на це конкретне питання, але ті, хто шукає відповіді на тему «як витончено вийти зі сценарію R», напевно, потраплять сюди. Здається, розробники R забули реалізувати функцію exit (). У будь-якому випадку, фокус, який я знайшов:

continue <- TRUE

tryCatch({
     # You do something here that needs to exit gracefully without error.
     ...

     # We now say bye-bye         
     stop("exit")

}, error = function(e) {
    if (e$message != "exit") {
        # Your error message goes here. E.g.
        stop(e)
    }

    continue <<-FALSE
})

if (continue) {
     # Your code continues here
     ...
}

cat("done.\n")

В основному, ви використовуєте прапор для позначення продовження чи ні вказаного блоку коду. Потім ви використовуєте stop()функцію для передачі спеціального повідомлення обробнику помилок tryCatch()функції. Якщо обробник помилок отримує ваше повідомлення для виходу з тонким виходом, тоді він просто ігнорує помилку та встановлює прапор продовження на FALSE.


0

Ви можете використовувати pskillфункцію в Rпакеті "Інструменти", щоб перервати поточний процес і повернутися до консолі. Конкретно, у мене є така функція, визначена у файлі запуску, який я створюю на початку кожного сценарію. Однак ви також можете скопіювати його безпосередньо на початку коду. Потім вставте halt()в будь-яку точку коду, щоб зупинити виконання сценарію на льоту. Ця функція добре працює на GNU / Linux, і, судячи з Rдокументації, вона також повинна працювати на Windows (але я не перевіряв).

# halt: interrupts the current R process; a short iddle time prevents R from
# outputting further results before the SIGINT (= Ctrl-C) signal is received 
halt <- function(hint = "Process stopped.\n") {
    writeLines(hint)
    require(tools, quietly = TRUE)
    processId <- Sys.getpid() 
    pskill(processId, SIGINT)
    iddleTime <- 1.00
    Sys.sleep(iddleTime)
}

> pskill (processId, SIGINT) закриває сеанс і навіть вилучає користувача з RStudio. Це досить небезпечно, але функціонально ....
Еспанта

Не знав, що RStudio вийде з ладу, але те саме питання обговорюється в: stackoverflow.com/questions/32820534/… Однак у Linux моє рішення працює нормально. Його перевага перед stopifnot полягає в тому, що повідомлення про помилку stopifnot () не відображається.
Франсуа Тонно

Я перевірив Windows, і він поводиться божевільно. Все одно, дякую. Мені подобається pskill.
Espanta

0

Тут:

if(n < 500)
{
    # quit()
    # or 
    # stop("this is some message")
}
else
{
    *insert rest of program here*
}

Обидва quit()і stop(message)вийде з вашого сценарію. Якщо ви отримуєте скрипт із командного рядка R, тоді quit()також вийде з R.


7
Поганою практикою є розміщення відповідей, які дублюють вже розміщені.
Томас

@Thomas, яка відповідь дублюється? Я бачу лише цю відповідь, використовуючи як зупинку, так і вихід, і фактично пояснюючи різницю між ними.

@Thomas: Поясніть, яку саме відповідь дублює моя відповідь.
stackoverflowuser2010

@Thomas: Я поставив запитання стосовно вашої критики. Чекаю, поки ви, будь ласка, дайте на нього відповідь.
stackoverflowuser2010

5
Відповідь @ netskink використовує stop(), і ОП вже зазначив у коментарях, що вони не хочуть quit()...
Бен Болкер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.