2013-08-20 2 views
6

Я пишу некоторые функции для выполнения повторяющихся задач, но я стараюсь свести к минимуму количество раз, когда я загружаю данные. В основном у меня есть одна функция, которая берет некоторую информацию и делает сюжет. Затем у меня есть вторая функция, которая будет циклически проходить и выводить несколько графиков в .pdf. В обеих функциях у меня есть следующие строки кода:Вложенные функции выбора окружения

if(load.dat) load("myworkspace.RData") 

где load.dat является логическим и данные мне нужно хранится в myworkspace.RData. Когда я вызываю функцию-обертку, которая пересекает и выводит несколько графиков, я не хочу перезагружать рабочее пространство в каждом вызове внутренней функции. Я думал, что могу просто загрузить рабочую область один раз в функцию обертки, тогда внутренняя функция могла бы получить доступ к этим данным, но я получил сообщение об ошибке в противном случае.

Так что я понял, что функция не может найти переменную в своей локальной среде (созданной при вызове функции), функция будет искать родительскую среду для переменной.

Я предположил, что родительская среда для внутреннего вызова функции будет внешним вызовом функции. Очевидно, что это не так:

func1 <- function(...){ 
    print(var1) 
} 

func2 <- function(...){ 
    var1 <- "hello" 
    func1(...) 
} 

> func2() 
Error in print(var1) : object 'var1' not found 

После прочтения многочисленных вопросов, язык руководство и this действительно полезный блог, я придумал следующее:

var1 <- "hello" 
save(list="var1",file="test.RData") 
rm(var1) 

func3 <- function(...){ 
    attach("test.RData") 
    func1(...) 
    detach("file:test.RData") 
} 

> func3() 
[1] "hello" 

Есть ли лучший способ сделать это? Почему не func1 ищет неопределенные переменные в локальной среде, созданные func2, когда это было func2, что называется func1?

Примечание: Я не знал, как назвать этот вопрос. Если у кого-то есть лучшие предложения, я изменю его и отредактирую эту строку.

+2

лексической области видимости означает, что функция будет искать неопределенные символы в своей родительской среде, которая не обязательно вызывающая среда. Проверьте это также: https://github.com/hadley/devtools/wiki/Environments –

+0

@ Ferdinand.kraft Спасибо за ссылку. Сегодня я проработаю. – dayne

+0

Если ваши данные в форме данных, вы можете использовать пакет 'data.table' и передать свои таблицы в качестве аргумента функции func1 внутри' func3'. Этот пакет работает по ссылке и не создает нежелательных копий ваших данных. –

ответ

7

Чтобы проиллюстрировать лексическую область видимости, необходимо учитывать следующее:

Во-первых, давайте создадим среду песочнице, только чтобы избежать о так общий R_GlobalEnv:

sandbox <-new.env() 

Теперь мы помещаем в него две функции: f, которая ищет переменную с именем x; и g, который определяет локальный x и называет f:

sandbox$f <- function() 
{ 
    value <- if(exists("x")) x else "not found." 
    cat("This is function f looking for symbol x:", value, "\n") 
} 

sandbox$g <- function() 
{ 
    x <- 123 
    cat("This is function g. ") 
    f() 
} 

Формальность: ввод определений функций в консоли вызывает то, чтобы иметь среду ограждающего набора для R_GlobalEnv, поэтому мы вручную заставить корпуса f и g соответствовать окружающей среды, в которой они «принадлежат»:

environment(sandbox$f) <- sandbox 
environment(sandbox$g) <- sandbox 

Адрес g. Локальная переменная x=123 не найден f:

> sandbox$g() 
This is function g. This is function f looking for symbol x: not found. 

Теперь мы создаем x в глобальной окружающей среде и вызвать g.Функция f будет искать x первым в песочнице, а затем в родителю песочнице, который бывает R_GlobalEnv:

> x <- 456 
> sandbox$g() 
This is function g. This is function f looking for symbol x: 456 

Просто чтобы проверить, что f ищет x первый в своем корпусе, мы можем поставить x там и называют g:

> sandbox$x <- 789 
> sandbox$g() 
This is function g. This is function f looking for symbol x: 789 

Вывод: символ поиска в R следует цепь вмещающих сред, не кадры оценки созданного во время выполнения вложенной функции звонки.

EDIT: Просто добавить ссылку на this very interesting answer from Martin Morgan on the related subject of parent.frame() vs parent.env()

+0

Это лучшая иллюстрация, которую я видел. Спасибо огромное! Я не понимал разницы в средах и кадрах. – dayne

2

Вы можете использовать укупорочные:

f2 <- function(...){ 
    f1 <- function(...){ 
    print(var1) 
    } 
    var1 <- "hello" 
    f1(...) 
} 
f2() 
+0

Правильно, но мне нужно иметь возможность использовать внутреннюю функцию как автономную функцию. Я не хотел переопределять внутреннюю функцию каждый раз, когда я вызываю внешнюю функцию (не говоря уже о дублировании кучи кода). – dayne

+0

Тогда самая чистая настройка на мой взгляд: поместите все свои данные в список (my_data), а затем дайте ее как аргумент вашей функции. Внутри функции вы можете использовать (my_data, {}), чтобы избежать дополнительной набрав. –

Смежные вопросы