Подтвердить что ты не робот

Глобальные переменные в пакетах в R

Я разрабатываю пакет в R. У меня есть куча функций, некоторым из которых нужны некоторые глобальные переменные. Как управлять глобальными переменными в пакетах?

Я кое-что прочитал об окружающей среде, но я не понимаю, как это будет работать, если это даже способ сделать это.

4b9b3361

Ответ 1

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

Для глобальных переменных в R см. этот SO post.

Изменить в ответ на ваш комментарий: Альтернативой может быть просто передать необходимую информацию тем функциям, которые в ней нуждаются. Вы можете создать новый объект, содержащий эту информацию:

token_information = list(token1 = "087091287129387",
                         token2 = "UA2329723")

и требуют, чтобы все функции, которые нуждались в этой информации, имели в качестве аргумента:

do_stuff = function(arg1, arg2, token)
do_stuff(arg1, arg2, token = token_information)

Таким образом, из кода видно, что в функции нужна токенная информация, и вы можете самостоятельно отлаживать эту функцию. Кроме того, функция не имеет побочных эффектов, так как ее поведение полностью определяется его входными аргументами. Типичный пользователь script будет выглядеть примерно так:

token_info = create_token(token1, token2)
do_stuff(arg1, arg2, token_info)

Надеюсь, это упростит ситуацию.

Ответ 2

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

pkg.env <- new.env()

pkg.env$cur.val <- 0
pkg.env$times.changed <- 0

inc <- function(by=1) {
    pkg.env$times.changed <- pkg.env$times.changed + 1
    pkg.env$cur.val <- pkg.env$cur.val + by
    pkg.env$cur.val
}

dec <- function(by=1) {
    pkg.env$times.changed <- pkg.env$times.changed + 1
    pkg.env$cur.val <- pkg.env$cur.val - by
    pkg.env$cur.val
}

cur <- function(){
    cat('the current value is', pkg.env$cur.val, 'and it has been changed', 
        pkg.env$times.changed, 'times\n')
}

inc()
inc()
inc(5)
dec()
dec(2)
inc()
cur()

Ответ 3

Вы можете установить option, например

options("mypkg-myval"=3)
1+getOption("mypkg-myval")
[1] 4

Ответ 4

Вопрос неясен:

  • Только один процесс R или несколько?

  • Просто на одном хосте или на нескольких машинах?

  • Есть ли общий доступ к файлам среди них или нет?

В возрастающем порядке сложности я бы использовал файл, бэкэнд SQLite через RSQlite или (мой любимый:) rredis для установки/чтения из экземпляра Redis.

Ответ 5

Вы также можете создать список токенов и добавить его в R/sysdata.rda с помощью usethis::use_data(..., internal = TRUE). Данные в этом файле являются внутренними, но доступны для всех функций. Единственная проблема может возникнуть, если вы хотите, чтобы к функциям обращались только некоторые функции, которые лучше обслуживались бы:

  1. решение для окружающей среды, уже предложенное выше; или
  2. создание скрытой вспомогательной функции, которая содержит токены и возвращает их. Затем просто вызовите эту скрытую функцию внутри функций, которые используют токены, и (при условии, что это список) вы можете внедрить их в их среду с помощью list2env(..., envir = environment()).