【问题标题】:R object's name carrying through multiple functionsR 对象的名称承载多个功能
【发布时间】:2023-04-01 17:29:01
【问题描述】:

根据我对Hadley's advice on building S3 objects 的阅读,我正在使用辅助函数、构造函数和验证器函数。一个简单的可重现示例:

test_object <- function(x, y, z) {
    new_test_object(x, y, z)
}

new_test_object <- function(x, y, z) {
    structure(list(x = x,
                   y = y,
                   z = z,
                   x_name = deparse(substitute(x))),
              class = "test_object")
}

validate_test_object <- function(test_object) {
    # Anything goes
    test_object
}

我希望生成的对象包含一个值,该值具有传入的项目的原始名称(上例中的$x_name)。如果我直接调用构造函数,deparse(substitute(...)) 技巧就会起作用:

alpha = "a"
test_constructor <- new_test_object(x = alpha, y = "b", z = "c")
test_constructor$x_name
# [1] "alpha"

但如果我使用辅助函数则不会:

test_helper <- test_object(x = alpha, y = "b", z = "c")
test_helper$x_name
# [1] "x"

我希望test_helper$x_name 也返回[1] "alpha"

没有在帮助器阶段执行deparse(substitute(...)) 步骤,构造函数(new_test_object())是否可以通过帮助器访问对象x 的“原始”名称?或者确保它的名字随着辅助函数传递给构造函数而传递?

【问题讨论】:

    标签: r nse r-s3


    【解决方案1】:

    这里的真正目的是什么?如果您只是将一个函数用作另一个函数的包装器,那么有更好的方法来保存参数。例如

    test_object <- function(x, y, z) {
      call <- match.call()
      call[[1]]  <- quote(new_test_object)
      eval(call)
    }
    

    但总的来说,依靠deparse() 从变量名称中获取信息并不是一种非常可靠的方法。如果您愿意,最好让这些信息成为您可以设置的适当参数。这使您的功能更加灵活。

    test_object <- function(x, y, z, xname=deparse(substitute(x))) {
        new_test_object(x, y, z, xname=xname)
    }
    
    new_test_object <- function(x, y, z, xname=deparse(substitute(x))) {
        structure(list(x = x,
                       y = y,
                       z = z,
                       x_name = xname),
                  class = "test_object")
    }
    

    【讨论】:

    • 诚实回答“这里的真正目的是什么?”:因为哈德利这么说!他的逻辑是帮助器“为其他人提供了一种方便且简洁的参数化方式来构造和验证(创建)这个类的对象。”。我喜欢您的建议或对其进行适当的参数化-看起来很整洁,并且可以很好地解决问题。谢谢!
    【解决方案2】:

    这里有一个不漂亮的解决方法:当你从另一个函数调用它时,添加 ... 参数来传递名称

    test_object <- function(x, y, z) {
      x_name = deparse(substitute(x))
      new_test_object(x, y, z, x_name = x_name)
    }
    
    new_test_object <- function(x, y, z, ...) {
      args <- list(...)
      if(is.null(args[["x_name"]])){
        structure(list(x = x,
                       y = y,
                       z = z,
                       x_name = deparse(substitute(x))),
                  class = "test_object")
      }
      else{
        structure(list(x = x,
                       y = y,
                       z = z,
                       x_name = args[["x_name"]]),
                  class = "test_object")
      }
    
    }
    

    结果如下:

    test_helper <- test_object(x = alpha, y = "b", z = "c")
    test_helper$x_name
    # [1] "alpha"
    

    【讨论】:

      猜你喜欢
      • 2019-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多