【问题标题】:How to persistently store value of an object instead of its name?如何持久存储对象的值而不是其名称?
【发布时间】:2014-05-19 13:41:07
【问题描述】:

这是我相关问题的延续:Error when trying to interactively load data file saved by paused batch script。我决定用一个可重现的例子单独提出我的问题,以避免使上一个问题中已经很大的描述变得更大。在以下可重现的示例中,我希望检索存储对象(“重要数据”)的 ,但正如您所见,我检索的是 对象本身的名称(“sf.data.devLinks”)。我怀疑这可能是因为我使用了as.name,但我在交互式会话中另外测试了一个原始示例,as.name 工作正常。如您所见,我也尝试过使用evalsubstitute,但没有帮助。

library(RCurl)

info <- "Important data"
ATTR <- "SQL"
request <- "SELECT info FROM topSecret"
dataName <- "sf.data.devLinks"
rdataFile <- "/tmp/testAttr.rds"

save <- TRUE

getData <- function() {
  return (info)
}

requestDigest <- base64(request)

# check if the archive file has already been processed
message("\nProcessing request \"", request, "\" ...\n")

# read back the object with the attribute
if (file.exists(rdataFile)) {
  # now check if request's SQL query hasn't been modified
  data <- readRDS(rdataFile)
  message("Retrieved object '", data, "', containing:\n")
  message(str(data))

  requestAttrib <- attr(data, ATTR, exact = TRUE)
  if (is.null(requestAttrib)) {
    message("Object '", data, "' doesn't have attribute \"",
            ATTR, "\"\n")
  }
  else {
    message("Object '", data, "' contains attribute ", ATTR, ":\n\"",
            base64(requestAttrib), "\"\n")

    if (identical(requestDigest, requestAttrib)) {
      message("Processing skipped: RDS file is up-to-date.\n")
      save <- FALSE
      return
    }
  }
  rm(data)
}

if (save) {
  message("Saving results of request \"",
          request, "\" as R data object ...\n")

  assign(dataName, getData())
  data <- as.name(dataName)
  #eval(substitute(assign(dataName, getData()),
  #                list(data <- as.name(dataName))))

  # save hash of the request's SQL query as data object's attribute,
  # so that we can detect when configuration contains modified query
  attr(data, ATTR) <- base64(request)

  # save current data frame to RDS file
  saveRDS(data, rdataFile)
}

请注意,测试此代码需要运行两次(第一次运行 - 存储对象,第二次 - 检索)。

【问题讨论】:

  • 等一下。最后,您希望名为 what 的对象包含 what data?这还不完全清楚。
  • @SimonO'Hanlon:我希望名为sf.data.devLinks 的对象具有Important data 的值和SQL 的属性,包含base64 编码的request。属性部分符合预期,但值部分不是。

标签: r variables object persistence metaprogramming


【解决方案1】:

问题在于您使用as.name,而不是在保存对象的代码中。这工作得很好:

data        <- 1:10
object.name <- 'data.name'
query       <- 'SELECT * FROM TABLE'
file        <- tempfile()
assign(object.name, structure(data, SQL = query))
saveRDS(get(object.name), file)
read.object <- readRDS(file)
identical(read.object, get(object.name))

您正在创建一个名称对象,并为其分配属性,但您希望数据存在。不会的,symbol 只是指向该值的指针。您需要使用 eval() 或类似的方法从 symbol 获取值。

【讨论】:

  • 感谢您的帮助!我之前意识到这一点,现在我正在敲定解决方案。成功测试后将发布解决方案。
【解决方案2】:

最后,我能够回到这个问题。我已经找到了正确的解决方案,所以我正在回答我自己的问题。这里的答案是基于我的reproducible example,但我已经在我更复杂的真实世界 R 代码中进行了相应的更改。 解决方案相当简单,但双重,如下。

  1. 将原代码data &lt;- readRDS(rdataFile)替换为assign(dataName, readRDS(rdataFile))

  2. 将原代码as.name(dataName)替换为get(dataName)。这里get() 的替代品是eval(parse(text=dataName)),恕我直言,这更麻烦。

下面我提供了解决方案的完整源代码,基于原始的可重现示例。我不提供脚本的输出,这很容易重现(记得至少运行两次脚本)。再次感谢所有帮助解决这个问题的人。

library(RCurl)

info <- "Important data"
ATTR <- "SQL"
request <- "SELECT info FROM topSecret"
dataName <- "sf.data.devLinks"
rdataFile <- "/tmp/testAttr.rds"

save <- TRUE

getData <- function() {
  return (info)
}

requestDigest <- base64(request)

# check if the archive file has already been processed
message("\nProcessing request \"", request, "\" ...\n")

# read back the object with the attribute
if (file.exists(rdataFile)) {
  # now check if request's SQL query hasn't been modified
  assign(dataName, readRDS(rdataFile))
  message("Retrieved object '", dataName, "', containing:\n")
  message(str(get(dataName)))

  requestAttrib <- attr(get(dataName), ATTR, exact = TRUE)
  if (is.null(requestAttrib)) {
    message("Object '", dataName, "' doesn't have attribute \"",
            ATTR, "\"\n")
  }
  else {
    message("Object '", dataName, "' contains attribute \"",
            ATTR, "\":\n\"", base64(requestAttrib), "\"\n")

    if (identical(requestDigest, requestAttrib)) {
      message("Processing skipped: RDS file is up-to-date.\n")
      save <- FALSE
      return
    }
  }
}

if (save) {
  message("Saving results of request \"",
          request, "\" as R data object ...\n")

  assign(dataName, getData())
  message(str(dataName))
  data <- get(dataName)
  # alternative to using get(), but more cumbersome:
  # data <- eval(parse(text=dataName))

  # save hash of the request's SQL query as data object's attribute,
  # so that we can detect when configuration contains modified query
  attr(data, ATTR) <- base64(request)

  message(str(data))

  # save current data frame to RDS file
  saveRDS(data, rdataFile)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 2013-03-31
    • 1970-01-01
    • 2014-08-06
    • 2011-10-13
    • 2011-04-17
    • 1970-01-01
    相关资源
    最近更新 更多