Область видимости блестящего объекта R

Я пытаюсь получить доступ к объекту (a<-get(obj1,envir=parent.environment())), находящемуся в вызывающей среде, из вызываемой среды myf, и я не могу заставить его работать. Ошибка, которую я получаю, это Object obj1 not found. Я пробовал parent.frame()тоже. Любые идеи?

library(shiny)
shinyApp(
  ui = textOutput("test1"),
  server = function(input, output) {
    myf <- function(x) {
      a <- get(obj1, envir = parent.environment())
      return(paste0(x,a))
    }
    output$test1 <- renderText({
      obj1 <- "testing"
      a <- lapply(c("a","b","c"), myf)
      return(paste(unlist(a), collapse = ","))
    })
  }
)

ПРИМЕЧАНИЕ. Я НЕ хочу создавать obj1 с помощью obj1<<-, поскольку он создается в глобальной среде и доступен для всех сеансов.


person Sri    schedule 09.09.2015    source источник


Ответы (2)


Правильное решение состоит в том, что у вас есть три проблемы: во-первых, вам нужно закавычить "obj1" вот так

get("obj1", envir = ...)

Во-вторых, parent.environment() не является функцией. Его не существует.

В-третьих, вам нужно немного разбираться в среде и вызывать фреймы, чтобы знать, как это работает (это не имеет ничего общего с Shiny). То, что вы хотите использовать, это parent.frame(2) (нахождение внутри lapply добавляет слой)

Итак, чтобы изменить исходный код, это решение:

library(shiny)
shinyApp(
  ui = textOutput("test1"),
  server = function(input, output) {
    myf <- function(x) {
      a <- get("obj1", envir = parent.frame(2))
      return(paste0(x,a))
    }
    output$test1 <- renderText({
      obj1 <- "testing"
      a <- lapply(c("a","b","c"), myf)
      return(paste(unlist(a), collapse = ","))
    })
  }
)
person DeanAttali    schedule 09.09.2015
comment
Ой, я даже не заметил, что "obj1" не было в кавычках. Неудивительно! - person shadowtalker; 10.09.2015
comment
Я заметил это только тогда, когда исправил проблему parent.environment как правильную среду, и все еще получал ошибку, и подумал, но я в правильной среде ..... почему! ах.. - person DeanAttali; 10.09.2015
comment
Отлично, спасибо за подробное объяснение daattali. Я должен больше узнать о вызове фреймов - есть хорошие ссылки? - person Sri; 10.09.2015
comment
Да, Хэдли, конечно: p adv-r.had.co.nz/Environments.html — отличное 30-минутное чтение, которое действительно многому вас научит - person DeanAttali; 10.09.2015
comment
@Sri Я рад, что вы получили свой ответ, но пусть это будет предупреждением о том, чтобы полагаться на область видимости вместо явной передачи аргументов. - person shadowtalker; 10.09.2015
comment
@daattali На самом деле я не понимаю, зачем здесь вообще нужен get. Например, f <- function(x) x + y; y <- 3; f(2) прекрасно работает. - person shadowtalker; 10.09.2015
comment
@ssdecontrol пример, который вы только что привели, сильно отличается. y сохраняется в глобальном масштабе, а внутри функции f при ссылке на y ее можно легко найти, просмотрев окружающую ее среду. Однако в случае с этим блестящим приложением obj1 создается внутри среды, которая вызывает myf, но НЕ является окружающей средой (где объявлено myf). Вы должны понимать, что родительская среда и окружающая среда — разные вещи. Прочтите ссылку Я отправил сообщение в книгу Хэдли.Если переменные будут искать в среде того, кто их вызывает, вы получите недетерминированный код = плохой - person DeanAttali; 10.09.2015
comment
@daattali Я читал эту статью, но это было давно. Таким образом, f <- function(x) x + y; g <- function(x) { y <- 3; f(x) }; g(2) может быть MWE для такого поведения. Идея состоит в том, что f вызывается из среды в g, но среда в g не является предком f. Верно? - person shadowtalker; 10.09.2015
comment
Как бы. Поиск переменных происходит в зависимости от того, где функция была ОПРЕДЕЛЕНА, а не там, где она ВЫЗЫВАЕТСЯ. f определяется в глобальном окружении, поэтому любые переменные внутри него должны быть найдены либо внутри f, либо в глобальном окружении. То же самое касается g. Если вы определили другую функцию h внутри f, то переменные внутри h могли использовать любую переменную из h или f или глобальную. Перечитывание его статьи было бы хорошим освежением - person DeanAttali; 10.09.2015

Я не уверен, почему это не работает, но есть простой обходной путь: явно передать obj1 в myf:

library(shiny)
shinyApp(
  ui = textOutput("test1"),
  server = function(input, output) {

## myf now takes two arguments, x and a:
    myf <- function(x, a) {
      return(paste0(x, a))
    }

    output$test1 <- renderText({
      obj1 <- "testing"

## Now you can just pass obj1 as a second argument to myf
##  without worrying about scoping:
      a <- lapply(c("a","b","c"), myf, obj1)

      return(paste(unlist(a), collapse = ","))
    })
  }
)
person shadowtalker    schedule 09.09.2015
comment
Спасибо за обходной путь, у вас также есть решение для определения области видимости - мне интересно посмотреть, что это за решение? - person Sri; 09.09.2015
comment
Вы можете увидеть мой ответ, чтобы увидеть правильное решение, а не обходной путь - person DeanAttali; 10.09.2015