Chr*_*oph 3 attributes r class
来自高级 R 第 3.3 节:
您可能已经注意到,原子向量集不包括许多重要的数据结构,例如矩阵、数组、因子或日期时间。这些类型是通过添加属性构建在原子向量之上的。
来自高级 R 第 3.4 节:
最重要的向量属性之一是类,它是 S3 对象系统的基础。拥有类属性会将对象转换为 S3 对象,这意味着当传递给通用函数时,它的行为将与常规向量不同。每个 S3 对象都构建在基本类型之上,并且通常在其他属性中存储附加信息。
因此,我想说,“阶级”不仅仅是“属性”。另一方面,它似乎data.frame可以充当attribute但实际上并非如此class。那么典型的用例是什么?(当然,我可以查看现有代码。但这感觉更像是糟糕的逆向工程,而不是“知道你在做什么”)
示例:我应该使用
mydata <- c(1:10)
attr(mydata, "x") <- "x-attribute"
attributes(mydata)
# $x
# [1] "x-attribute"
Run Code Online (Sandbox Code Playgroud)
或者
mydata <- c(1:10)
class(mydata) <- "x"
class(mydata)
# [1] "x"
attributes(mydata)
# $class
# [1] "x"
Run Code Online (Sandbox Code Playgroud)
在后一种情况下,
print.x <- function(x) print.default(paste0("This is ", paste(x, collapse = " / ")))
plot.x <- function(x) plot.default(rep(1, length(x)), x, xlab = "great", main = "x")
print(mydata)
# [1] "This is 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 10"
plot(mydata)
Run Code Online (Sandbox Code Playgroud)
按预期工作。但哪个“更好”呢?
属性data.frame似乎没有用:
mydata <- c(1:10)
attr(mydata, "x") <- "x-attribute"
attr(mydata, "y") <- data.frame(x=c(1, 2), y=c(3, 4))
attributes(mydata)
# $x
# [1] "x-attribute"
#
# $y
# x y
# 1 1 3
# 2 2 4
Run Code Online (Sandbox Code Playgroud)
(无法使print.???或plot.???工作......)
“class”属性决定通用方法调度。数据框的“class”属性设置为字符串“data.frame”,这使得诸如 之类的通用函数format甚至print数学运算符可以将其与数值向量等不同地对待。
类以外的属性以不同的方式使用,通常用于存储类正常工作所需的信息,但在不需要时可以对用户隐藏。
例如,分组tibble具有存储为属性的向量row.names,列名称存储为属性内的字符向量,以及存储在 tibble 内的组作为名为 的属性groups。后者是作为属性存储并执行有用工作的数据框的一个很好的示例。
as_tibble(iris) %>% group_by(Species) %>% attr('groups')
#> # A tibble: 3 x 2
#> Species .rows
#> <fct> <list<int>>
#> 1 setosa [50]
#> 2 versicolor [50]
#> 3 virginica [50]
Run Code Online (Sandbox Code Playgroud)
此属性通常对最终用户隐藏,因为它不是由 tibble 的print方法打印的,但它对于分组 tibble 正常工作至关重要。
很容易设置一个示例来展示如何在单个对象中使用类和其他属性。假设我们希望能够在对象创建时为其添加时间戳,以便它保留其创建日期的记录,但我们不希望用户看到它,除非他们特别要求。
首先,我们有一个类创建器(顺便说一句,这可能是创建类的最佳方式,而不是简单地设置类属性)
timestamp <- function(x) {
structure(x, created_on = Sys.Date(), class = c('timestamp', class(x)))
}
Run Code Online (Sandbox Code Playgroud)
现在我们创建一个不显示时间戳的打印方法。
print.timestamp <- function(x) {
attr(x, 'created_on') <- NULL
class(x) <- class(x)[-1]
NextMethod()
}
Run Code Online (Sandbox Code Playgroud)
最后,我们可以创建一个小通用函数来检查创建的对象的时间戳。如果对象没有时间戳,则应返回错误:
creation_date <- function(x) UseMethod('creation_date')
creation_date.default <- function(x) stop('No timestamp on this object')
creation_date.timestamp <- function(x) {
attr(x, 'created_on')
}
Run Code Online (Sandbox Code Playgroud)
现在测试一下,我们可以创建一个带有时间戳的对象,它看起来与无时间戳的对象完全一样:
object <- timestamp(1:10)
object
#> [1] 1 2 3 4 5 6 7 8 9 10
Run Code Online (Sandbox Code Playgroud)
但在雷达之下,它包含该对象可能需要按预期运行的其他有用信息:
creation_date(object)
#> [1] "2022-09-30"
Run Code Online (Sandbox Code Playgroud)