Проще объяснить, что происходит, чем это исправить. Если мы начнем с рассмотрения обобщенного 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 способом написания пакета для других пользователей.
Тем не менее, приятно знать это возможно возможно