问题
This is in continuation of my related question: Error when trying to interactively load data file saved by paused batch script. I decided to present my question with a reproducible example separately to avoid making the already large description in the previous question even bigger. In the following reproducible example, I expect to retrieve the value of the stored object ("Important data"), but instead, as you see, I retrieve the name of the object itself ("sf.data.devLinks"). I suspected that it could be because of me using as.name, but I tested additionally a primitive example in an interactive session and as.name worked fine. I also, as you see, have tried using eval and substitute, but it didn't help.
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)
}
Please note that testing this code requires running it twice (first run - to store the object, second - to retrieve).
回答1:
The problem is in your use of as.name, not in the code to save the object. This works perfectly fine:
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))
You're creating a name object, and assigning attributes to it, but you're expecting the data to be there. It won't be, a symbol is just a pointer to the value. You need to use eval() or something similar to get the value from the symbol.
回答2:
Finally, I was able to return to this question. I have figured out the correct solution, so I'm answering my own question. The answer here is based on my reproducible example, but I have made corresponding changes in my more complex real-world R code. The solution is rather simple, but twofold, as follows.
Replace the original code
data <- readRDS(rdataFile)withassign(dataName, readRDS(rdataFile)).Replace the original code
as.name(dataName)withget(dataName). An alternative toget()here iseval(parse(text=dataName)), which IMHO is more cumbersome.
Below I provide the solution's full source code, based on the original reproducible example. I don't provide the script's output, which is easy to reproduce (remember to run script at least twice). Again, thanks to everyone who helped with this question.
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)
}
来源:https://stackoverflow.com/questions/23739359/how-to-persistently-store-value-of-an-object-instead-of-its-name