2017-01-10 78 views
0

我的全局環境中有一個名爲myList的變量。我有一個功能,修改myList並重新分配給稱爲myFunction的全球環境。我只想要myList被修改myFunction。有沒有辦法阻止任何其他功能修改myList限制哪些功能可以修改對象

爲了背景,我正在爲R用戶構建一個通用工具。我不希望該工具的用戶能夠定義他們自己的功能來修改myList。我也不想讓自己能夠修改myList與我將來可能寫的函數。

我有一個潛在的解決方案,但我不喜歡它。執行該工具時,我可以檢查用戶定義的每個函數的文本,並搜索將爲全球環境分配myList的文本。我不喜歡我需要搜索所有功能的事實。

有誰知道我在找什麼可以在R中實現?感謝您提供的任何幫助。

對於可重現的示例。我需要的代碼,這將使下面的例子可能:

assign('myList', list(), envir = globalenv()) 
myFunction <- function() { 
    myList <- c(myList, 'test') 
    assign('myList', myList, envir = globalenv()) 
} 
userFunction <- function() { 
    myList <- c(myList, 'test') 
    assign('myList', myList, envir = globalenv()) 
} 
myFunction() # I need some code that will allow this function to run successfully 
userFunction() # and cause an error when this function runs 
+0

我不認爲應該如此限制 - 你應該看看S3類,也許最好的解決方案將是幾乎有你自己的數據結構和方法獨特的類。因爲你的數據不是由函數創建的,而是被修改的 - 初始輸入總是可以自由地做任何事情。 – zacdav

回答

1

聽起來像是你需要的modules包。

基本上,每個代碼單元都有自己的範圍。

例如

# install.packages("modules") 
# Load library 
library("modules") 

# Create a basic module 
m <- module({ 
    .myList <- list() 
    myFunction <- function() { 
     .myList <<- c(.myList, 'test') 
    } 

    get <- function() .myList 
}) 
# Accessor 
m$get() 
# list() 

# Your function 
m$myFunction() 

# Modification 
m$get() 
# [[1]] 
# [1] "test" 

注意,我們從myList改變變量名.myList小幅微調的例子。所以,我們需要更新,在userfunction()

userFunction <- function() { 
    .myList <- c(.myList, 'test') 
} 

運行這個,現在我們得到:

userFunction() 
# Error in userFunction() : object '.myList' not found 

如期望的那樣。

欲瞭解更詳細的例子,請參閱modules vignette

另一種方法是您可以定義環境(new.env()),然後在加載myList後將其鎖定。

1

這是一個壞主意。從分配到全球環境開始(我絕不會使用這樣做的包)來讓用戶感到驚訝。你應該只使用S4或引用類。

無論如何,你可以鎖定綁定(或環境,如果你遵循更好的做法)。你不會阻止高級用戶,但他們至少知道你不希望他們改變對象。

createLocked <- function(x, name, env) { 
    assign(name, x, envir = env) 
    lockBinding(name, env) 
    invisible(NULL) 
} 

createLocked(list(), "myList", globalenv()) 


myFunction <- function() { 
    unlockBinding("myList", globalenv()) 
    myList <- c(myList, 'test') 
    assign('myList', myList, envir = globalenv()) 
    lockBinding("myList", globalenv()) 
    invisible(NULL) 
} 

userFunction <- function() { 
    myList <- c(myList, 'test') 
    assign('myList', myList, envir = globalenv()) 
} 

myFunction() # runs successfully 
userFunction() 
#Error in assign("myList", myList, envir = globalenv()) : 
# cannot change value of locked binding for 'myList'