简短版:
使用 inherits
,但在处理数字和 S4 类时要小心。
详细版:
从 is
帮助页面的“另请参阅”部分:
对于 S4 和非 S4 对象,inherits 几乎总是等价于 is,并且速度略快。不相等适用于具有条件超类的类,在关系(不常见且不鼓励)中存在非平凡测试的类:对于这些类,is 测试关系,但根据定义,inherits 忽略 S4 对象的条件继承。
来自 inherits
帮助页面的“正式类”部分:
正式类的 inherits 类比为 is。这两个函数行为一致,除了一个例外:S4 类可以具有条件继承和显式测试。在这种情况下,is 将测试条件,但 inherits 忽略所有条件超类。
因此,它们大多返回相同的结果,但 inherits
更快,因此在大多数情况下应该是默认选择。(正如 Konrad 所提到的,is
还需要加载 methods
包,这可能使其不适合对性能敏感的 Rscript
使用场景。)
如果您正在使用具有条件继承的 S4 类,则这两个函数的值可能会有所不同,但是这是 不推荐的(请参见“方法选择和分派:详细信息”部分),因此希望很少发生。
两个函数最明显不同之处在于检查整数是否为数字时。
class(1L)
## [1] "integer"
is.numeric(1L)
## [1] TRUE
is(1L, "numeric")
## [1] TRUE
inherits(1L, "numeric")
## [1] FALSE
?class
,如果对象没有类属性,则具有隐式类,“"matrix"”,“"array"”或‘mode(x)’的结果(除了整数向量具有隐式类“"integer"”)。我可以想象(??)is
查看隐式类而inherits
不会...? - Ben Bolkeris
函数在 methods
包中,而该包默认情况下在运行 Rscript
时不会加载(因为加载速度较慢)。相比之下,inherits
函数属于 base
包,因此在 R 脚本程序中随时可用。 - Konrad Rudolphis()
和inherits()
,我们还可以使用is.*()
测试特定类型的对象。这三个函数可能会返回不同的结果。根据这个答案,我做了以下操作:
storage.mode()
、mode()
、typeof()
和class()
提取了这些对象的类型。is()
、inherits()
和is.*()
测试这些对象是否属于返回的类型。# Get object classes withs torage.mode(), mode(), typeof() and class().
obj <- logical()
(types <- c(storage.mode= storage.mode(obj),
mode= mode(obj),
type= typeof(obj),
class= class(obj)))
storage.mode mode type class
"double" "numeric" "double" "numeric"
# Test returned types with is, inhertis and is.*.
> is(obj, "double"); is(obj, "numeric")
[1] FALSE
[1] TRUE
> inherits(obj, "double"); inherits(obj, "numeric")
[1] FALSE
[1] TRUE
> is.double(obj); is.numeric(obj)
[1] TRUE
[1] TRUE
# Generate objects of different types.
library(xml2)
setClass("dummy", representation(x="numeric", y="numeric"))
obj <- list(
"logical vector" = logical(),
"integer vector" = integer(),
"numeric vector" = numeric(),
"complex vector" = complex(),
"character vector" = character(),
"raw vector" = raw(),
"factor" = factor(),
"logical matrix" = matrix(logical()),
"numeric matrix" = matrix(numeric()),
"logical array" = array(logical(8), c(2, 2, 2)),
"numeric array" = array(numeric(8), c(2, 2, 2)),
"list" = list(),
"pairlist" = .Options,
"data frame" = data.frame(),
"closure function" = identity,
"builtin function" = `+`,
"special function" = `if`,
"environment" = new.env(),
"null" = NULL,
"formula" = y ~ x,
"expression" = expression(),
"call" = call("identity"),
"name" = as.name("x"),
#"paren in expression" = expression((1))[[1]], # Code fails with this
#"brace in expression" = expression({1})[[1]], # Code fails with this
"S3 lm object" = lm(dist ~ speed, cars),
"S4 dummy object" = new("dummy", x = 1:10, y = rnorm(10)),
"external pointer" = read_xml("<foo><bar /></foo>")$node
)
# Extract types and test them.
res <- do.call("rbind.data.frame", Map(function(x, name){
types <- c(storage.mode= storage.mode(x),
mode= mode(x),
type= typeof(x),
class= class(x))
data.frame("object"= name,
"extract_method"= names(types),
"extract_result"= types,
"inherits"= sapply(types, function(i) inherits(x, i)),
"is"= sapply(types, function(i) is(x, i)),
"is.type"= sapply(types, function(i) eval(parse(text= paste0("tryCatch({is.", i, "(x)}, error= function(e){'is.", i, "() does not exist'})"))))
)}, obj, names(obj)))
rownames(res) <- 1:nrow(res)
res <- res[order(res$extract_method), ]
res
中得到一些见解。例如,我们可以看到is.()
和inherits()
不返回相同的结果:> res[res$inherits != res$is, ]
object extract_method extract_result inherits is is.type
6 integer vector mode numeric FALSE TRUE TRUE
87 call storage.mode language FALSE TRUE TRUE
89 call type language FALSE TRUE TRUE
inherits()
返回 FALSE
的地方等等。我在这里省略了这些内容。实际上,我认为我的答案更加全面,因为它考虑了提取和测试对象类型之间的差异。在阅读了关于对象类型的大量资料后,我得出了上面的代码并想分享给大家。但是,仅使用 res[res$inherits != res$is, ]
就可以回答问题。
"character" %in% class(letters)
?根据这篇文章我理解它相当于inherits,只不过速度较慢,但我不确定。 - moodymudskipperis.list(iris)
为TRUE
,但"list" %in% class(iris)
和inherits(iris,"list")
为FALSE
,这对于区分数据框和列表很有用。我是否应该理解,在所有情况下都建议使用inherits
,而后两者实际上是等价的?顺便说一句,你不错的datacamp课程把我带到了这里。 - moodymudskipper