理解 attr(x, "class") 和 class(x) 之间的区别
Understanding difference between attr(x, "class") and class(x)
背景
我正在查看 Romain François 提出的 jazz 包。 Romain 使用以下语法定义函数 is_bare_vector
:
is_bare_vector <- function(x) {
is_vector(x) && !is.object(x) && is.null(attr(x, "class"))
}
问题
对于:x <- 1
:
attr(x, "class")
# NULL
鉴于:
class(x)
# [1] "numeric"
我想了解为什么这两个函数提供不同的答案? ?attr
上的帮助参考 ?class
?attr
Note that some attributes (namely class
, comment
, dim
, dimnames
,
names
, row.names
and tsp
) are treated specially and have restrictions
on the values which can be set. (Note that this is not true of levels
which should be set for factors via the levels replacement function.)
?class
Many R objects have a class attribute, a character vector giving the
names of the classes from which the object inherits. (Functions
oldClass
and oldClass<-
get and set the attribute, which can also be
done directly.)
您只需要在 help("class")
中进一步阅读:
If the object does not have a class attribute, it has an implicit class, notably "matrix", "array", "function" or "numeric" or the result of typeof(x) (which is similar to mode(x))
显然,如果 class 属性是 NULL
,class()
也会 return 隐含的 class;让我们检查一下 C source code --
我们看到如果 class 属性的长度为 0,它会得到 implicit class.:
SEXP R_data_class(SEXP obj, Rboolean singleString)
{
SEXP value, klass = getAttrib(obj, R_ClassSymbol);
int n = length(klass);
if(n == 1 || (n > 0 && !singleString))
return(klass);
if(n == 0) {
SEXP dim = getAttrib(obj, R_DimSymbol);
int nd = length(dim);
if(nd > 0) {
if(nd == 2)
klass = mkChar("matrix");
else
klass = mkChar("array");
}
else {
SEXPTYPE t = TYPEOF(obj);
switch(t) {
case CLOSXP: case SPECIALSXP: case BUILTINSXP:
klass = mkChar("function");
break;
case REALSXP:
klass = mkChar("numeric");
break;
case SYMSXP:
klass = mkChar("name");
break;
case LANGSXP:
klass = lang2str(obj, t);
break;
default:
klass = type2str(t);
}
}
}
else
klass = asChar(klass);
PROTECT(klass);
value = ScalarString(klass);
UNPROTECT(1);
return value;
}
背景
我正在查看 Romain François 提出的 jazz 包。 Romain 使用以下语法定义函数 is_bare_vector
:
is_bare_vector <- function(x) {
is_vector(x) && !is.object(x) && is.null(attr(x, "class"))
}
问题
对于:x <- 1
:
attr(x, "class")
# NULL
鉴于:
class(x)
# [1] "numeric"
我想了解为什么这两个函数提供不同的答案? ?attr
上的帮助参考 ?class
?attr
Note that some attributes (namely
class
,comment
,dim
,dimnames
,names
,row.names
andtsp
) are treated specially and have restrictions on the values which can be set. (Note that this is not true of levels which should be set for factors via the levels replacement function.)
?class
Many R objects have a class attribute, a character vector giving the names of the classes from which the object inherits. (Functions
oldClass
andoldClass<-
get and set the attribute, which can also be done directly.)
您只需要在 help("class")
中进一步阅读:
If the object does not have a class attribute, it has an implicit class, notably "matrix", "array", "function" or "numeric" or the result of typeof(x) (which is similar to mode(x))
显然,如果 class 属性是 NULL
,class()
也会 return 隐含的 class;让我们检查一下 C source code --
我们看到如果 class 属性的长度为 0,它会得到 implicit class.:
SEXP R_data_class(SEXP obj, Rboolean singleString)
{
SEXP value, klass = getAttrib(obj, R_ClassSymbol);
int n = length(klass);
if(n == 1 || (n > 0 && !singleString))
return(klass);
if(n == 0) {
SEXP dim = getAttrib(obj, R_DimSymbol);
int nd = length(dim);
if(nd > 0) {
if(nd == 2)
klass = mkChar("matrix");
else
klass = mkChar("array");
}
else {
SEXPTYPE t = TYPEOF(obj);
switch(t) {
case CLOSXP: case SPECIALSXP: case BUILTINSXP:
klass = mkChar("function");
break;
case REALSXP:
klass = mkChar("numeric");
break;
case SYMSXP:
klass = mkChar("name");
break;
case LANGSXP:
klass = lang2str(obj, t);
break;
default:
klass = type2str(t);
}
}
}
else
klass = asChar(klass);
PROTECT(klass);
value = ScalarString(klass);
UNPROTECT(1);
return value;
}