2015-03-10 14 views
9

C'è un modo per lanciare un avviso (e fallire ..) se una variabile globale viene utilizzata all'interno di una funzione R? Penso che sia molto più efficace e prevenga comportamenti non voluti ... ad es.Scopo: non consentire le variabili globali nella funzione

sUm <- 10 
sum <- function(x,y){ 
sum = x+y 
return(sUm) 
} 

a causa della "errore di battitura" in cambio la funzione restituirà sempre 10. Invece di restituire il valore di sUm dovrebbe fallire.

+2

Vedere: [questa domanda] (http://stackoverflow.com/questions/25373447/how-to-detect-free-variable-names-in-r-functions) o [questa domanda] (http: // stackoverflow.com/questions/21245850/making-sure-a-function-does-not-use-a-global-variable) o [questa domanda] (http://stackoverflow.com/questions/6216968/r-force- ambito locale) per ulteriori discussioni. – MrFlick

risposta

6

altra mia risposta è più su quale approccio si può prendere all'interno vostra funzione. Ora fornirò alcune informazioni su cosa fare una volta definita la tua funzione.

Per garantire che la funzione non stia utilizzando le variabili globali quando non dovrebbe essere, utilizzare il pacchetto codetools.

library(codetools) 

sUm <- 10 
f <- function(x, y) { 
    sum = x + y 
    return(sUm) 
} 

checkUsage(f) 

Questo stamperà il messaggio:

<anonymous> local variable ‘sum’ assigned but may not be used (:1)

per vedere se tutte le variabili globali sono stati utilizzati nella funzione, è possibile confrontare l'output della funzione findGlobals() con le variabili nell'ambiente globale.

> findGlobals(f) 
[1] "{" "+" "=" "return" "sUm" 

> intersect(findGlobals(f), ls(envir=.GlobalEnv)) 
[1] "sUm" 

che ti dice che la variabile sUm globale è stato utilizzato all'interno f() quando probabilmente non avrebbe dovuto essere.

+0

questa è una bella! un modo semplice per verificare se le variabili globali sono utilizzate in modo errato in una funzione. Non sapevo quel pacchetto. Grazie! – Jonas

+0

@ Jonas: Felice di poterti aiutare. –

3

Utilizzando get è un modo:

sUm <- 10 
sum <- function(x,y){ 
    sum <- x+y 
    #with inherits = FALSE below the variable is only searched 
    #in the specified environment in the envir argument below 
    get('sUm', envir = environment(), inherits=FALSE) 
} 

uscita:

> sum(1,6) 
Error in get("sUm", envir = environment(), inherits = FALSE) : 
    object 'sUm' not found 

Avere il giusto sum in funzione get sarebbe ancora guardare solo all'interno dell'ambiente della funzione per la variabile, il che significa che se non ci erano due variabili, una all'interno della funzione e una nell'ambiente globale con lo stesso nome, la funzione avrebbe sempre cercato la variabile all'interno dell'ambiente della funzione e mai nell'ambiente globale:

sum <- 10 
sum2 <- function(x,y){ 
    sum <- x+y 
    get('sum', envir = environment(), inherits=FALSE) 
} 

> sum2(1,7) 
[1] 8 
3

È possibile verificare se il nome della variabile viene visualizzato nell'elenco di variabili globali. Nota che questo è imperfetto se la variabile globale in questione ha lo stesso nome di un argomento della tua funzione.

if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv)) 
    stop("Do not use a global variable!") 

La funzione stop() arresterà l'esecuzione della funzione e visualizzare il messaggio di errore dato.

5

Non esiste un modo per modificare in modo permanente il modo in cui le variabili vengono risolte poiché ciò interromperà molte funzioni. Il comportamento che non ti piace è in realtà molto utile in molti casi.

Se una variabile non viene trovata in una funzione, R verificherà l'ambiente in cui è stata definita la funzione per tale variabile. È possibile modificare questo ambiente con la funzione environment(). Ad esempio

environment(sum) <- baseenv() 
sum(4,5) 
# Error in sum(4, 5) : object 'sUm' not found 

Questo funziona perchè baseenv() punti all'ambiente "base" che è vuoto. Tuttavia, si noti che non si ha accesso ad altre funzioni con questo metodo

myfun<-function(x,y) {x+y} 
sum <- function(x,y){sum = myfun(x+y); return(sUm)} 

environment(sum)<-baseenv() 
sum(4,5) 
# Error in sum(4, 5) : could not find function "myfun" 

perché in un linguaggio funzionale come R, le funzioni sono solo le variabili regolari che sono anche come ambito nell'ambiente in cui vengono definiti e non sarebbe disponibile nell'ambiente di base.

Dovresti modificare manualmente l'ambiente per ogni funzione che scrivi. Anche in questo caso, non è possibile modificare questo comportamento predefinito poiché molte delle funzioni e delle funzioni R di base definite nei pacchetti si basano su questo comportamento.

+0

che ne dici di una funzione che fa questo per te? –

+1

Bene, hai ancora il problema che non è facile distinguere tra una "variabile" e una "funzione" in R. Per essere utile, probabilmente vorrai avere accesso a tutte le funzioni nello spazio dei nomi. ma a volte potresti voler scrivere funzioni che restituiscono altre funzioni. Non è ovvio per me che aspetto avrebbe un involucro appropriato. – MrFlick

2

Un altro modo (o lo stile) è quello di mantenere tutte le variabili globali in un ambiente speciale:

with(globals <- new.env(), { 
    # here define all "global variables" 
    sUm <- 10 
    mEan <- 5 
}) 

# or add a variable by using $ 
globals$another_one <- 42 

Poi la funzione non sarà in grado di farli:

sum <- function(x,y){ 
    sum = x+y 
    return(sUm) 
} 

sum(1,2) 
# Error in sum(1, 2) : object 'sUm' not found 

ma è possibile usali sempre con i globali $:

globals$sUm 
[1] 10 

Per gestire la disciplina, è possibile verificare se esiste un v globale ariable (ad eccezione di funzioni) al di fuori del globals:

setdiff(ls(), union(lsf.str(), "globals")))