break / exit komut dosyası


87

Biraz veri analizi yapan ve birkaç yüz satır uzunluğunda bir programım var.

Programın çok erken safhalarında, biraz kalite kontrol yapmak istiyorum ve yeterli veri yoksa programın sonlandırılmasını ve R konsoluna geri dönmesini istiyorum. Aksi takdirde, kodun geri kalanının çalışmasını istiyorum.

Denedim break, browserve quitve bunların hiçbiri programın geri kalanında yürütülmesini durdurmak (ve quitben olmasını istediğim bir şey değil de tamamen bırakma R gibi yürütme durdurur). Son çarem if-elseaşağıdaki gibi bir ifade oluşturmaktır :

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

ama bu kötü bir kodlama uygulaması gibi görünüyor. Bir şey mi kaçırıyorum?


4
quitçoğu durumda programın geri kalanının çalışmasını durdurur. Lütfen tekrarlanabilir bir örnek sağlayın .
Joshua Ulrich

@JakeBurkhead - yukarıdaki kodum (boş bir if ifadesiyle) o zaman gitmenin en iyi yolu mu? @Joshua Ulrich, quittüm R'den çıkar, ancak programın amaçlarım için açık kalması gerektiğinden R konsoluna geri dönmek istiyorum.
user2588829

Bir programla neyi kastediyorsunuz? Yazdığınız bir işlevi çalıştırdığınızı mı yoksa bir komut dosyasından kaynak mı aldığınızı mı söylüyorsunuz?
Gavin Simpson

if-else muhtemelen bunun üstesinden gelmenin doğru yoludur. İstisnalar, her şeyin doğru kullanılması durumunda olmaması gereken durumlar içindir. Olabilecek bir şeyse ve bununla nasıl başa çıkacağınızı biliyorsanız, normal kontrol akışını kullanın.
Matthew

Yanıtlar:


62

stopifnot()Programın bir hata üretmesini istiyorsanız işlevi kullanabilirsiniz :

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

+1! Sanırım işlev foo, komut dosyasının başlangıcı olarak adlandırılmalı ve diğer doğrulama kontrollerini içermelidir ...
agstudy

22
stopifnotkullanışlıdır, ancak kullanılarak hazırlanmış bir yanıt if(x < 500) { stop("Not enough observations in 'x': n < 500")}tercih edilebilir. Ayrıca bu konuyu ele, bir toplu iş için bir şey, eğer olmadan bir hata yararlıdır atma.
Gavin Simpson

4
OP'yi karıştırmayı bırak. İstediği şey stopifnot () değil, quit () veya stop ().
stackoverflowuser2010

10
@ stackoverflowuser2010 O istemiyor quit(soruya bakın!) Hatta sanmıyorum stopait stopifnotbu işlemek için en iyi yoldur; stopbir hata atarsa, tüm komut dosyası iptal olur. İken stopifnot(ya da stop) Yanıt OP hatasız, temiz çıkış için bir işlev yazma, en çok sevdiği gibi görünüyor, durumların daha geniş bir aralıkta daha faydalıdır. Büyük veri analizi işleri için çok sayıda uzun süre çalışan komut dosyası yazmış olmak, sorunu ele almak ve temiz bir şekilde geri dönmek yerine hata atan işlevlerden daha can sıkıcı değildir. Ama açıkça neden bahsettiğimi bilmiyorum ...
Gavin Simpson

@GavinSimpson'da hata atma konusundaki yorumunuzu netleştirebilir misiniz? Denediğimde stop("my message")terminale yazdırıyorum Error: "my message" Execution halted. Yani bu bir hata mesajı çıktısı gösteriyor, ancak bir hata "atmadığını" mı söylüyorsunuz? (yani, hata olarak çağırdığı komut dosyalarından herhangi biri varsa, iptal edilmek üzere ayarlanmış bir toplu işi durdurmaz). Teşekkürler! (Şu anda senaryoyu Rscript ile arıyorum)
rrr

14

Hoş değil, ama işte exit()benim için çalışan bir komutu R'de uygulamanın bir yolu .

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

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

Sadece hafifçe test edildi, ancak bunu çalıştırdığımda this is the last message, komut dosyası herhangi bir hata mesajı olmadan iptal edildiğini görüyorum .


Olumsuz tarafı, CRAN paketinde kod için izin verilmemesidir. Yani CRAN'a yüklemek istediğiniz bir pakette kullanmayı düşünürseniz R CMD CHECK,.
MS Berends

1
Evet, bu daha çok bir sistem işlevine benziyor. Yorumlayıcının dahili detayları değiştirilirse kırılabilir, bu nedenle ayrı bir paket yerine R çekirdeğinin bir parçası olabilir mi? Bunu, bir hata mesajı gönderilmeden yorumlayıcıdan çıkmak için doğru yere nasıl gidebileceğimi görmek için R kaynak kodu üzerinden farklı yolları izleyerek buldum. Oraya varmak için bulduğum pek çok yol yoktu; bu yüzden kullanıyorum .invokeRestartve sonra da .Internal.
jochen

Ah evet, CRAN politikaları dışında bence güzel bir çözüm! Size +10 tekrar göndermeme izin verin;)
MS Berends

tuhaf. Bunu yeni denedim ve son çıktı satırı [1] "bunu görmemelisiniz" R sürümü 3.4.3 (2017-11-30) Platform: x86_64-pc-linux-gnu (64-bit) Altında çalışan: Red Hat Enterprise Linux Server sürüm 6.10 (Santiago)
CodingMatters

2
Onunla çalışmasını exit <- function() { invokeRestart("abort") }
sağladım

12

If-else yapınızı tersine çevirin:

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

2
yeterince basit ve sanırım yapabileceğimin en iyisi bu olabilir, teşekkürler
user2588829

9

Düzenleme: OP'nin uzun bir komut dosyası çalıştırdığı görülüyor, bu durumda yalnızca komut dosyasının kalite kontrolünden sonra

if (n >= 500) {

.... long running code here

}

Bir işlevin dışına çıkıyorsanız, muhtemelen return()açıkça veya örtük olarak isteyeceksiniz .

Örneğin, açık bir çift dönüş

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

İma return()edilmekle, son satırın sanki yapmışsınız gibi olduğunu söylüyorum return(xx), ancak görüşmeyi bırakmak biraz daha etkilidir return().

Bazıları birden çok dönüşü kötü stil kullanmayı düşünür; uzun işlevlerde, işlevin nerede çıktığını takip etmek zorlaşabilir veya hataya açık hale gelebilir. Bu nedenle bir alternatif, tek bir dönüş noktasına sahip olmak, ancak tümceyi kullanarak dönüş nesnesini değiştirmektir if () else (). Böyle bir değişiklik foo()olacak

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

Bunu da düşündüm, ancak OP'nin bir işlevden kurtulmaktan bahsettiği net değil.
Thomas

Evet, Thomas haklı - Bir işlevden kurtulmaktan bahsetmiyorum.
user2588829

1
@ user2588829 Bunu 100+ satırlık bir komut dosyası yerine R'ye bir işlev olarak koymanız çok daha iyi olur.
Gavin Simpson

@GavinSimpson oh, hala R'de yeniyim, bu yüzden bunu bilmiyordum. 100'den fazla satır işlevi olarak tanımlarsam, bu daha iyi bir uygulama olur mu?
user2588829

1
@ user2588829 Evet, çok daha iyi. Fonksiyonun argümanlarını kontrol edersiniz, böylece gerekli olanı iletebilirsiniz. Ayrıca, analizi çalıştırmak için 100'den fazla kod satırı kullanmak yerine, sadece yaptığınız myFun(arg1, arg2, arg3)vb. Şeyleri organize etmenin çok daha iyi bir yoludur.
Gavin Simpson

9

Belki de bir noktada uzun bir komut dosyasını yürütmeyi bırakmak istersiniz. yani. C veya Python'da bir çıkışı () sabit kodlamak istediğiniz gibi.

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

1
Bu kod için hata mesajını alıyorum Error in eval(expr, envir, enclos) :.
jochen

2
Evet, infaz gerçekten durur. Tesadüfen, veya stop()ile değiştirirseniz , komut dosyası da durur (elbette yalnızca hata mesajları farklıdır). exit()please.stop.now()
jochen

1
@jochen Komutun içine alıntılanmış bir ifade eklemek, stop()bu "hatayı" diğer mesajlardan ayırt etmeye yardımcı olabilir. Örneğin: tek başına stop("Manual break inserted here")olduğundan daha bilgilendirici olabilir stop().
Omar Wasow

3

Bu eski bir soru ama henüz temiz bir çözüm yok. Muhtemelen bu belirli soruyu yanıtlamıyor, ancak 'bir R betiğinden zarif bir şekilde nasıl çıkılır' sorusuna yanıt arayanlar muhtemelen buraya inecek. Görünüşe göre R geliştiricileri bir exit () işlevini uygulamayı unutmuş. Her neyse, bulduğum numara:

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")

Temel olarak, belirli bir kod bloğunun devam edip etmediğini belirtmek için bir bayrak kullanırsınız. Ardından stop(), bir tryCatch()işlevin hata işleyicisine özelleştirilmiş bir mesaj iletmek için işlevi kullanırsınız. Hata işleyici, nazikçe çıkmak için mesajınızı alırsa, hatayı yok sayar ve devam bayrağını olarak ayarlayın FALSE.


0

Mevcut işlemi kesmek ve konsola geri dönmek için "araçlar" paketindeki pskillişlevi kullanabilirsiniz R. Somut olarak, her komut dosyasının başında kaynak oluşturduğum bir başlangıç ​​dosyasında aşağıdaki işlevi tanımlıyorum. Bununla birlikte, bunu doğrudan kodunuzun başında da kopyalayabilirsiniz. Ardından halt()komut dosyasının çalıştırılmasını anında durdurmak için kodunuzun herhangi bir noktasına ekleyin . Bu işlev GNU / Linux üzerinde iyi çalışıyor ve Rbelgelere bakılırsa Windows üzerinde de çalışıyor olmalı (ama kontrol etmedim).

# 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) oturumu kapatır ve kullanıcıyı RStudio'dan bile çıkarır. Oldukça tehlikeli ama işlevsel ....
Espanta

RStudio'yu çökerteceğini bilmiyordum, ancak aynı sorun şu adreste tartışılıyor: stackoverflow.com/questions/32820534/… Linux üzerinde yine de çözümüm iyi çalışıyor. Stopifnot'a göre avantajı, stopifnot () Hata mesajının görünmemesidir.
François Tonneau

Windows'u kontrol ettim ve çılgınca davranıyor. Yine de teşekkürler. Doktor becerisini seviyorum.
Espanta

0

Buraya:

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

Her ikisi de quit()ve stop(message)betiğinizden çıkacak. Komut dosyanızı R komut isteminden kaynaklıyorsanız, o quit()zaman R'den de çıkacaktır.


7
Zaten gönderilmiş olan yanıtları çoğaltmak kötü bir uygulamadır.
Thomas

@Thomas bu hangi cevabı tekrarlıyor? Sadece bu cevabı hem durdur hem de bırak kullanarak görüyorum ve aslında aralarındaki farkı açıklıyor.

@Thomas: Cevabımın tam olarak hangi cevabın yinelendiğini açıklayın.
stackoverflowuser2010

@Thomas: Eleştirinizle ilgili bir soru sordum. Lütfen cevaplamanı bekliyorum.
stackoverflowuser2010

5
@ netskink'in cevabı kullanıyor stop()ve OP istemediklerini yorumlarda zaten belirtiyor quit()...
Ben Bolker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.