Код в вопросе определяет функцию в глобальной среде. Мы можем запросить ее окружение следующим образом:
environment(e10$testfun)
## <environment: R_GlobalEnv>
Когда функция ищет свободную переменную (которая указана, но не определена в функции), например testvar
, она использует среду функции (и ее предков). ) найти переменную. testvar
находится в e4
, но e4
не является предком глобальной среды, поэтому в вопросе testvar
не найдено.
Другие среды не имеют значения. Если функция вызывается, то среда вызывающей стороны (также известная как родительский фрейм) не играет никакой роли в поиске переменных. Точно так же, если функция позже помещается где-то еще (в данном случае e10
), эта среда также не играет роли в поиске переменных. Кроме того, следует понимать, что когда функция, о которой идет речь, помещается в e10
, она уже была определена в глобальной среде, и поэтому глобальная среда уже была установлена в качестве ее среды. Функция состоит из аргументов, тела и среды (и таких атрибутов, как класс), и перемещение функции в другое место не меняет ни одну из этих составляющих.
Исправление
Нам необходимо явно установите для окружения testfun
значение e10
, если мы хотим, чтобы оно имело это в качестве окружения и чтобы e4
было предком:
environment(e10$testfun) <- e10
или, альтернативно, мы не могли определить testfun
в глобальном окружении, в первую очередь, а точнее определить testfun
в окружении e10
с самого начала:
with(e10, {
testfun <- function() testvar
})
e10$testfun()
## [1] 1200
Имена функций
Может быть еще одна путаница заблуждение, что следующий оператор определяет функцию с именем testfun
в e10
.
e10$testfun <- function() testvar
Проблема этой идеи заключается в том, что функции не имеют имен. Три составляющих функции - это аргументы, тело и окружение (и такие атрибуты, как class и, возможно, srcref и scrfile). Имя не является составной частью функции. Можно поместить функцию в переменную и ссылаться на эту переменную, как если бы это было имя функции, но на самом деле это просто переменная, которая содержит функцию, а имя не является частью самой функции. Таким образом, в приведенной выше строке кода мы не определяем функцию с именем testfun; скорее, мы определяем анонимную функцию (в глобальной среде) и затем перемещаем ее в переменную testfun
.
Пример из самого R *
Хотя она является общей для пользовательских функций оставаться в среде, в которой они определены, например, функции
f <- function() "hello"
# the environment of f
environment(f)
## <environment: R_GlobalEnv>
# the environment where f is located (same)
as.environment(find("f"))
## <environment: R_GlobalEnv>
в R-пакетах на пути поиска
# show search path
search()
обычно не расположены в их окружающая обстановка. Для любой функции в пакете в пути поиска функция будет иметь пространство имен пакета в качестве своего окружения, но при доступе к функции оно будет найдено не в пространстве имен, а в другой среде.
# the environment of function mean
e1 <- environment(mean); e1
## <environment: namespace:base>
# where mean is located
e2 <- as.environment(find("mean")); e2
## <environment: base>
# these are NOT the same
identical(e1, e2)
## [1] FALSE
Это хорошо показано на диаграммах в этом посте: http://blog.obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/
proto
Существует пакет, который работает так, как этого ожидает вопрос. Прото-объекты похожи на среды, но если вы назначаете им функцию, то среда функции меняется на ту, на которую они назначены. (Есть и другие отличия, но мы сосредоточимся на этом.)
Сначала мы определяем объект прото p
, родительским объектом которого является e9, а затем присваиваем интересующую функцию p
. Наконец мы запускаем эту функцию. (Первый аргумент неявно является объектом-прототипом, поэтому мы его опускаем.) Мы видим, что функция действительно сбросила свое окружение и что e4 теперь является предком своего окружения, не устанавливая его явно.
library(proto)
p <- proto(e9) # define proto object whose parent is e9
p$testfun <- function(self) testvar
identical(p, with(p, environment(testfun))) # testfun's environment is now p
## [1] TRUE
p$testfun()
## [1] 1200