สคริปต์ทำลาย / ออก


87

ฉันมีโปรแกรมที่วิเคราะห์ข้อมูลและมีความยาวไม่กี่ร้อยบรรทัด

ในช่วงแรกของโปรแกรมฉันต้องการควบคุมคุณภาพและหากมีข้อมูลไม่เพียงพอฉันต้องการให้โปรแกรมยุติและกลับไปที่คอนโซล R มิฉะนั้นฉันต้องการให้โค้ดที่เหลือทำงาน

ฉันได้พยายามbreak, browserและquitและไม่มีพวกเขาหยุดการทำงานของส่วนที่เหลือของโปรแกรม (และquitหยุดการดำเนินการเช่นเดียวกับการเลิกสูบบุหรี่อย่างสมบูรณ์ R ซึ่งเป็นสิ่งที่ฉันไม่ต้องการให้เกิดขึ้น) ทางเลือกสุดท้ายของฉันคือการสร้างif-elseคำสั่งดังต่อไปนี้:

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

แต่ดูเหมือนว่าการเขียนโค้ดไม่ดี ฉันพลาดอะไรไปรึเปล่า?


4
quitส่วนใหญ่หยุดการทำงานของโปรแกรมที่เหลืออย่างแน่นอน โปรดให้ตัวอย่างที่ทำซ้ำได้
Joshua Ulrich

@JakeBurkhead - รหัสของฉันข้างบน (มีคำสั่ง if ว่างเปล่า) เป็นวิธีที่ดีที่สุดใช่ไหม @Joshua Ulrich quitออกจาก R ทั้งหมด แต่ฉันต้องการกลับไปที่คอนโซล R เพราะโปรแกรมต้องยังคงเปิดอยู่เพื่อจุดประสงค์ของฉัน
user2588829

คุณหมายถึงอะไรโดยโปรแกรม? คุณหมายความว่าคุณกำลังเรียกใช้ฟังก์ชันที่คุณเขียนหรือคุณกำลังจัดหาสคริปต์หรือไม่?
Gavin Simpson

if-else น่าจะเป็นวิธีจัดการที่ถูกต้อง ข้อยกเว้นมีไว้สำหรับสถานการณ์ที่ไม่ควรเกิดขึ้นหากใช้ทุกอย่างอย่างถูกต้อง หากเป็นสิ่งที่สามารถเกิดขึ้นได้และคุณรู้วิธีจัดการให้ใช้ขั้นตอนการควบคุมปกติ
Matthew

คำตอบ:


62

คุณสามารถใช้stopifnot()ฟังก์ชันนี้ได้หากคุณต้องการให้โปรแกรมสร้างข้อผิดพลาด:

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

+1! ฉันเดาว่าฟังก์ชันfooควรถูกเรียกว่าจุดเริ่มต้นของสคริปต์และมีการควบคุมการตรวจสอบความถูกต้องอื่น ๆ ...
agstudy

22
stopifnotมีประโยชน์ แต่if(x < 500) { stop("Not enough observations in 'x': n < 500")}อาจต้องการการตอบสนองที่สร้างขึ้นโดยใช้ นอกจากนี้หากนี่เป็นงานแบทช์การจัดการปัญหาโดยไม่ทิ้งข้อผิดพลาดจะมีประโยชน์
Gavin Simpson

4
หยุดพยายามสับสน OP สิ่งที่เขาต้องการคือเลิก () หรือหยุด () ไม่ใช่หยุด ()
stackoverflowuser2010

10
@ stackoverflowuser2010 เขาไม่ต้องการquit(ดูคำถาม!) ฉันไม่ได้คิดว่าstopการstopifnotเป็นวิธีที่ดีที่สุดในการจัดการนี้; stopแสดงข้อผิดพลาดสคริปต์ทั้งหมดจะถูกยกเลิก ในขณะที่stopifnot(หรือstop) ดูเหมือนว่าคำตอบ OP ชอบที่สุด แต่การเขียนฟังก์ชันให้ออกอย่างหมดจดโดยไม่มีข้อผิดพลาดจะเป็นประโยชน์มากกว่าในสถานการณ์ที่หลากหลาย การเขียนสคริปต์ที่ใช้งานได้ยาวนานจำนวนมากสำหรับงานวิเคราะห์ข้อมูลขนาดใหญ่ไม่มีอะไรน่ารำคาญไปกว่าฟังก์ชันที่ทำให้เกิดข้อผิดพลาดแทนที่จะจัดการปัญหาและส่งคืนอย่างหมดจด แต่ชัดเจนว่าฉันไม่รู้ว่าฉันกำลังพูดถึงอะไร ...
Gavin Simpson

คุณช่วยชี้แจงความคิดเห็นของคุณเกี่ยวกับการส่งข้อผิดพลาด @GavinSimpson ได้ไหม เมื่อฉันพยายามที่ฉันได้รับการพิมพ์เข้ากับขั้วต่อstop("my message") Error: "my message" Execution haltedดังนั้นนี่จึงแสดงเอาต์พุตข้อความแสดงข้อผิดพลาด แต่คุณกำลังบอกว่ามันไม่ "โยน" ข้อผิดพลาดหรือไม่? (กล่าวคือจะไม่หยุดงานแบตช์ที่ถูกตั้งค่าให้ยกเลิกหากสคริปต์ใด ๆ ที่เรียกว่าข้อผิดพลาดในการโยน) ขอบคุณ! (ตอนนี้ฉันกำลังเรียกใช้สคริปต์ด้วย Rscript)
rrr

14

ไม่สวย แต่นี่คือวิธีใช้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-bit) ทำงานภายใต้: Red Hat Enterprise Linux Server เวอร์ชัน 6.10 (Santiago)
CodingMatters

2
ฉันใช้งานได้exit <- function() { invokeRestart("abort") }
Droplet

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 กำลังพูดถึงการแยกฟังก์ชันออก
Thomas

ใช่โทมัสพูดถูก - ฉันไม่ได้พูดถึงการแตกฟังก์ชันออกไป
user2588829

1
@ user2588829 คุณจะดีกว่ามากถ้าวางมันเป็นฟังก์ชั่นใน R แทนที่จะเป็นสคริปต์ 100+ บรรทัด
Gavin Simpson

@GavinSimpson โอ้ฉันยังใหม่กับ R เลยไม่รู้ว่า ถ้าฉันกำหนดเป็นฟังก์ชัน 100+ บรรทัดจะเป็นการปฏิบัติที่ดีกว่าหรือไม่?
user2588829

1
@ user2588829 ใช่ดีกว่า คุณควบคุมอาร์กิวเมนต์ของฟังก์ชันเพื่อให้สามารถส่งผ่านสิ่งที่จำเป็นได้ นอกจากนี้แทนที่จะจัดหาโค้ดกว่า 100 บรรทัดเพื่อรันการวิเคราะห์ที่คุณเพิ่งทำmyFun(arg1, arg2, arg3)เป็นต้นมันเป็นเพียงวิธีการจัดระเบียบสิ่งต่างๆที่ดีกว่ามาก
Gavin Simpson

9

บางทีคุณอาจต้องการหยุดเรียกใช้สคริปต์ที่ยาวในบางจุด กล่าวคือ. เช่นคุณต้องการฮาร์ดโค้ด exit () ใน 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()เพียงอย่างเดียว
Omar Wasow

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แพ็กเกจ "tools" เพื่อขัดจังหวะกระบวนการปัจจุบันและกลับไปที่คอนโซล ที่จริงฉันมีฟังก์ชันต่อไปนี้ที่กำหนดไว้ในไฟล์เริ่มต้นที่ฉันมาที่จุดเริ่มต้นของแต่ละสคริปต์ อย่างไรก็ตามคุณสามารถคัดลอกได้โดยตรงที่จุดเริ่มต้นของรหัสของคุณอย่างไรก็ตาม จากนั้นแทรก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 ด้วยซ้ำ ค่อนข้างอันตราย แต่ใช้งานได้ ....
Espanta

ไม่รู้ว่า RStudio จะขัดข้อง แต่มีการพูดถึงปัญหาเดียวกันใน: stackoverflow.com/questions/32820534/…บน linux วิธีแก้ปัญหาของฉันใช้งานได้ดี ข้อได้เปรียบของ stopifnot คือข้อความแสดงข้อผิดพลาด stopifnot () ไม่ปรากฏขึ้น
François Tonneau

ฉันตรวจสอบบน 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

@ โทมัสคำตอบนี้ซ้ำกันตรงไหน? ฉันเห็นเพียงคำตอบนี้โดยใช้ทั้งหยุดและเลิกและอธิบายความแตกต่างระหว่างคำตอบ

@ โทมัส: อธิบายว่าคำตอบของฉันซ้ำกันอย่างไร
stackoverflowuser2010

@ โทมัส: ฉันตั้งคำถามเกี่ยวกับคำวิจารณ์ของคุณ ฉันกำลังรอให้คุณช่วยตอบ
stackoverflowuser2010

5
คำตอบของ @ netskink ใช้stop()และ OP ระบุในความคิดเห็นแล้วว่าไม่ต้องการquit()...
Ben Bolker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.