Получение имени объекта, переданного в `print` при непосредственном вызове объекта (без выражения функции` print`) - PullRequest
4 голосов
/ 06 апреля 2020

Я пытаюсь определить метод печати для моего нового объекта и использовать имя объекта, переданное print с использованием deparse(substitute(y)). Это прекрасно работает, если явно использовать функцию print:

obj <- structure(list(x = 1), 
                 class = "new_obj")

print.new_obj <- function(y){
  cat("New object name:\n")
  print(deparse(substitute(y)))
}

print(obj)
# New object name:
#   [1] "obj"

Но когда объект вызывается по имени самостоятельно, результирующая функция print не определяет имя:

obj
# New object name:
#   [1] "x"

Существует ли стандартный способ изменить поведение неявного вызова на print при самостоятельной передаче имени объекта?

РЕДАКТИРОВАТЬ: изменил аргумент функции на y для представления объекта, являющегося объектом переданный, чтобы продемонстрировать, что "x" возвращается независимо от того, что во втором вызове.

1 Ответ

1 голос
/ 07 апреля 2020

Проще объяснить, что происходит, чем это исправить. Если мы начнем с рассмотрения обобщенного c print, то увидим, что он просто отправляет соответствующий классу print метод через UseMethod("print"):

print
#> function (x, ...) 
#> UseMethod("print")

Поэтому, когда вы вызываете print(obj), сначала вы вызываете функцию generi c print(obj), которая затем вызывает print.new_obj(obj). Мы можем подтвердить это, добавив print(sys.calls()) к вашему методу печати:

print.new_obj <- function(y){
  print(sys.calls())
  cat("New object name:\n")
  cat(deparse(substitute(y)))
}

print(obj)
#> [[1]]
#> print(obj)
#> 
#> [[2]]
#> print.new_obj(obj)
#> 
#> New object name:
#> obj

Пока все хорошо, и я подозреваю, что вы уже все это знали.

Что происходит сейчас, когда вы просто наберите obj в консоли?

obj
#> [[1]]
#> (function (x, ...) 
#> UseMethod("print"))(x)
#> 
#> [[2]]
#> print.new_obj(x)
#> 
#> New object name:
#> x

Теперь мы можем видеть, откуда взялся x. Он взят из закулисного вызова родового c print, который на самом деле называется безымянной функцией. Следовательно, имя переменной фактически не включено в стек вызовов. Есть другие вопросы о SO, где говорится, что это делает проблему неразрешимой. Это не правда; это просто означает, что вам нужно искать объект за пределами стека вызовов:

print.new_obj <- function(y){
  obj_name <- deparse(substitute(x, parent.frame()))
  if (obj_name != "x")
  {
    obj_name <- names(which(sapply(ls(envir = parent.frame(2)), function(v) 
      identical(y, get(v, envir = parent.frame(2))))))[1]
    cat("New object name:\n", obj_name)
  }
  else cat("New object name:\n", deparse(substitute(y)))
}

print(obj)
#> New object name:
#>  obj
obj
#> New object name:
#>  obj

Конечно, вы не захотите использовать это в рабочем коде по разным причинам. Не очень полезно или логично, чтобы структура данных знала, какому имени она была присвоена в конкретной среде, и не будет идиоматическим c способом написания пакета для других пользователей.

Тем не менее, приятно знать это возможно возможно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...