Вопросы

R Как проверить, вызывается ли пользовательская функция внутри определенной функции из определенного пакета

Я хочу создать функцию myfun, которую можно использовать только внутри другой функции, в моем случае dplyrs mutate или summarise. Я больше не хочу полагаться на dplyrс внутренностями (например mask$...).

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

search_calling_fn <- function(pattern) {
  
  call_st <- lapply(sys.calls(), `[[`, 1)
  
  res <- any(unlist(lapply(call_st, function(x) grepl(pattern, x, perl = TRUE))))
  
  if (!res) {
    stop("`myfun()` must only be used inside dplyr::mutate or dplyr::summarise")
  } else {
    return()
  }
}

Это работает, как и ожидалось, как показано в двух приведенных ниже примерах (dplyr = 1.0.0).

library(dplyr)

myfun <- function() {
  search_calling_fn("^mutate|^summarise")
  NULL
}

# throws as expected no error
mtcars %>% 
  mutate(myfun())


myfun2 <- function() {
  search_calling_fn("^select")
  NULL
}

# throws as expected an error
mtcars %>% 
  mutate(myfun2())

В этом подходе есть одна лазейка: myfun можно вызывать из функции с похожим именем, которая не является функцией dplyr. Интересно, как я могу проверить, из какого пространства имен приходит функция в моем стеке вызовов. rlang имеет функцию call_ns, но она будет работать только в том случае, если функция явно вызывается с package::.... Кроме того, при использовании mutate в стеке вызовов есть mutate_cols внутренняя функция и mutate.data.frame метод S3 — кажется, что оба делают получение пространства имен еще более сложным.

С другой стороны, мне интересно, есть ли лучший, более официальный подход для достижения того же результата: разрешить вызов myfun только в пределах dplyrs mutate или summarise.

Подход должен работать независимо от того, как вызывается функция:

  1. mutate
  2. dplyr::mutate

Дополнительное примечание

Читать:
Как изменить форму листа Excel с заголовком в три строки, чтобы упорядочить формат данных?

После обсуждения ответа @r2evans я понимаю, что решение должно пройти следующий тест:

library(dplyr)

myfun <- function() {
  search_calling_fn("^mutate|^summarise")
  NULL
}

# an example for a function masking dplyr's mutate
mutate <- function(df, x) {
  NULL
}

# should throw an error but doesn't
mtcars %>% 
  mutate(myfun())

Таким образом, функция проверки должна не только смотреть на стек вызовов, но и пытаться увидеть, из какого пакета исходит функция в стеке вызовов. Интересно, что отладчик RStudios показывает пространство имен для каждой функции в стеке вызовов, даже для внутренних функций. Интересно, как он это делает, ведь environment(fun)) работает только с экспортированными функциями.

Придирка: вам не хватает закрытия } в конце функции search_calling_fn.   —  person TimTeaFan    schedule 06.07.2020

Спасибо, что заметили это! Я исправил это.   —  person TimTeaFan    schedule 06.07.2020

Связано: 1 и 2.   —  person TimTeaFan    schedule 06.07.2020

Ваш пример кода mutate никогда не даст сбоев, потому что x ленив; поскольку он никогда не используется, он никогда не реализуется, поэтому myfun никогда не вызывается. … но я понимаю вашу точку зрения, getAnywhere в моем ответе слишком нетерпелив.   —  person TimTeaFan    schedule 08.07.2020

Похожие записи

Не можете установить пакет DateTime в Julia 1.0?

admin

Параметризация azureSubscription из группы переменных в конвейере yaml

admin

Есть ли способ преобразовать формат данных файла .pb из NCHW в NHWC?

admin

WPF добавляет новую строку в заполненную таблицу данных из БД

admin

rake db: миграция прерывается из-за разницы в версии rake

admin

Flutter / Dart получает изображение / данные из API на основе токена входа пользователя

admin