2017-08-25 35 views
2

我正在尋找一種方法來調用不受.GlobalEnv中其他對象影響的函數。強制R函數調用是自給自足的

採取下面來看看兩個功能:

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

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

在這種情況下:

  • f1(5)應失敗,因爲y沒有在功能範圍
  • f2(iris)應該通過定義因爲該函數沒有引用其範圍外的變量

現在,我可以覆蓋的f1f2環境,無論是baseenv()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 

或:

# 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 

有沒有辦法來覆蓋功能的環境,使其具有自給自足,但只要加載自己的庫,它也總是有效的?

+1

只要是什麼? –

+3

老實說,我只是不會編寫包含全局變量的函數 - 它似乎是一個意外錯誤的處方。 –

+1

可能相關:https://stackoverflow.com/q/6216968/324364 – joran

回答

3

這裏的問題是,從根本上,這library和類似的工具不提供作用域,而不是設計製造與範圍的工作:即使library是在函數內部執行時,它的效果實際上是全球,而不是本地。 呃。

具體而言,您從全球環境中分離功能的方法是聲音;然而,library操縱search路徑(通過attach),並且該函數的環境未被「通知」:它仍將指向之前的第二個搜索路徑條目作爲其祖父。

當您調用library/attach/...時,您需要找到更新的方法。你可以用函數的父級環境中的library等替換你自己的版本來實現這個功能,這個版本調用attach的修改版本。這attach2然後不僅會調用原來的attach,但也重新鏈接您的環境的父母。


順便說一句,‹modules›修復所有這些問題。在你的代碼中用modules::import_package('foo', attach = TRUE)代替library(foo)使其工作。這是因爲模塊的作用範圍很大,並且具有環境意識。

+0

是的,看起來沒有別的辦法。但爲了這個工作,這個被重寫的'library'版本需要被附加,我不確定我可以執行本地代碼,因爲潛在的非預期的副作用。 –