2017-08-25 4 views
2

Ich bin auf der Suche nach einer Möglichkeit, eine Funktion, die nicht von anderen Objekten in .GlobalEnv beeinflusst wird.Force R Funktionsaufruf zu autarken

Werfen Sie einen Blick auf die beiden folgenden Funktionen:

y = 3 
f1 = function(x) x+y 

f2 = function(x) { 
    library(dplyr) 
    x %>% 
     mutate(area = Sepal.Length *Sepal.Width) %>% 
     head() 
} 

In diesem Fall:

  • f1(5) ausfallen, weil y nicht
  • f2(iris) passieren sollte im Funktionsumfang definiert ist, weil die Funktion keine Variablen außerhalb ihres Gültigkeitsbereichs referenziert
Jetzt 363.210

, kann ich die Umgebung von f1 überschreiben und f2, entweder zu baseenv() oder new.env(parent=environment(2L)):

environment(f1) = baseenv() 
environment(f2) = baseenv() 
f1(3) # fails, as it should 
f2(iris) # fails, because %>% is not in function env 

oder:

# detaching here makes `dplyr` inaccessible for `f2` 
# not detaching leaves `head` inaccessible for `f2` 
detach("package:dplyr", unload=TRUE) 
environment(f1) = new.env(parent=as.environment(2L)) 
environment(f2) = new.env(parent=as.environment(2L)) 
f1(3) # fails, as it should 
f2(iris) # fails, because %>% is not in function env 

Gibt es eine Möglichkeit, eine Funktion die Umgebung zu überschreiben, so dass sie um autark zu sein, aber es funktioniert auch immer, solange es seine eigenen Bibliotheken lädt?

+1

Solange es was ist? –

+3

Ehrlich, ich würde einfach keine Funktionen schreiben, die globale Variablen enthalten - es scheint ein Rezept für unbeabsichtigte Fehler zu sein. –

+1

Möglicherweise relevant: https://stackoverflow.com/q/6216968/324364 – joran

Antwort

3

Das Problem hier ist, im Grunde, dass library und ähnliche Werkzeuge tun Scoping nicht bieten, und sind nicht mit Bereichen arbeiten gemacht werden entworfen: Obwohl library innerhalb der Funktion ausgeführt wird, ist seine Wirkung tatsächlich global, nicht lokal. Ugh.

Insbesondere ist Ihr Ansatz der Isolierung der Funktion von der globalen Umgebung Sounds; library manipuliert jedoch den Pfad search (über attach), und die Umgebung der Funktion wird nicht davon "benachrichtigt": Es wird weiterhin auf den vorherigen zweiten Suchpfadeintrag als Großelternteil zeigen.

Sie müssen einen Weg von Aktualisierung der Funktion Umgebung des Großeltern-Umgebung finden, wenn library/attach/... ist genannt. Sie können dies erreichen, indem Sie library usw. in der übergeordneten Umgebung der Funktion durch Ihre eigenen Versionen ersetzen, die eine modifizierte Version von attach aufrufen. Diese attach2 würde dann nicht nur das Original attach anrufen, sondern auch die Eltern der Umgebung neu verknüpfen.


Als Neben ‹modules› Fixes alle dieser Probleme. Ersetzen Sie library(foo) von modules::import_package('foo', attach = TRUE) in Ihrem Code macht es funktioniert. Dies liegt daran, dass Module stark eingeschränkt und umweltbewusst sind.

+0

Ja, es sieht so aus, als gäbe es keinen anderen Weg. Damit dies jedoch funktioniert, müsste diese überschriebene Version von "library" angehängt werden, was ich aufgrund von möglichen unbeabsichtigten Nebenwirkungen nicht für lokalen Code durchsetzen kann. –