is 和 inherits 有什么区别?

What's the difference between is and inherits?

提问人:Richie Cotton 提问时间:1/13/2015 最后编辑:Richie Cotton 更新时间:2/8/2022 访问量:12444

问:

如果我想检查变量是否继承自某个类,我可以使用 isinherits

class(letters)
## [1] "character"
is(letters, "character")
## [1] TRUE
inherits(letters, "character")
## [1] TRUE

对于我应该使用哪一个,是否有偏好,它们是否返回不同的值?

继承 R-FAQ

评论

0赞 moodymudskipper 6/12/2018
@Richie,当你们提出和回答这个问题时,你能包括在你的问题/答案中吗?我对这篇文章的理解是,它等同于继承,只是速度较慢,但我不确定。"character" %in% class(letters)
0赞 Richie Cotton 6/15/2018
@Moody_Mudskipper 是的,这也有效,尽管代码的意图不太清楚,所以我不确定你什么时候想使用它。
0赞 moodymudskipper 6/15/2018
例如,我在这个答案中使用了它: stackoverflow.com/questions/18746456/simplified-dput-in-r . 是 but 和 are ,这对于区分 data.frames 和列表很有用。我是否应该理解,敲钉子,后者确实是等价的,并且您建议在所有情况下?顺便说一句,你不错的 datacamp 课程把我带到了这里。is.list(iris)TRUE"list" %in% class(iris)inherits(iris,"list")FALSEinherits

答:

14赞 3 revsRichie Cotton #1

短版:

使用 ,但要小心数字和 S4 类。inherits


加长版:

在帮助页面的“另请参阅”部分:is

inherits 几乎总是等同于 is,无论是对于 S4 还是非 S4 对象,并且速度更快。非等同性适用于 具有条件超类的类,具有非平凡的 test= 在关系中(不常见且不鼓励):对于这些,是测试 关系,但根据定义继承,忽略条件 S4 对象的继承。

在帮助页面的“正式课程”部分:inherits

形式类的继承的类似物是 is。两个功能 行为一致,但有一个例外:S4 类可以有 条件继承,具有显式测试。在这种情况下,是将 测试条件,但 inherits 忽略所有条件超类。

因此,它们大多返回相同的内容,但速度更快,因此在大多数情况下,它应该是默认选择。(正如 Konrad 所提到的,还需要加载包,这可能使其不适合对性能敏感的 Rscript 使用。inheritsismethods

如果您使用具有条件继承的 S4 类,则这些值可能会有所不同,但不建议这样做(请参阅“方法选择和调度:详细信息”部分),这意味着希望很少见。

这两个函数最明显的地方是检查整数是否为数字时。

class(1L)
## [1] "integer"
is.numeric(1L)
## [1] TRUE
is(1L, "numeric")
## [1] TRUE
inherits(1L, "numeric")
## [1] FALSE

评论

1赞 Carl Witthoft 1/13/2015
好的,你能解释一下为什么整数不“继承”,而浮点数却“继承”: Rgames> 类(1.4) [1] “数字” Rgames> is.numeric(1.4) [1] 真 Rgames> inherits(1.4,'numeric') [1] 真 Rgames> is(1.4,'numeric') [1] 真
2赞 Ben Bolker 1/13/2015
我认为这可能与数字对象只有一个隐式类有关:从 ,我可以想象 (??) 查看隐式类并且不 ...??classIf the object does not have a class attribute, it has an implicit class, ‘"matrix"’, ‘"array"’ or the result of ‘mode(x)’ (except that integer vectors have implicit class ‘"integer"’).isinherits
0赞 Dieter Menne 1/13/2015
我记得无意中听到高R受试者的评论,称其为“劣势”。
3赞 Konrad Rudolph 1/19/2015
另一个非常关键的区别是,在默认情况下,包在运行时不会加载(因为它加载速度很慢)。相比之下,它来自 R 脚本程序,因此在 R 脚本程序中很容易获得。ismethodsRscriptinheritsbase
1赞 LulY 2/8/2022 #2

此外,我们还可以使用某种类型的对象进行测试。这三个函数可以返回不同的结果。根据这个答案,我做了以下工作is()inherits()is.*()

  • 创建了大量不同类型的 R 对象
  • 使用 、 和 提取了这些对象的类型。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), ]

我们可以从结果中得到一些见解。例如,我们可以 loow were does not return same as :resis.()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

当然,结果显示的远不止这些,例如,我们可以看到三种提取方法之一的类型返回了哪里,等等。我把这个留在这里。事实上,我认为我的答案要广泛得多,因为它考虑了对象类型提取测试的差异。在阅读了相当长的时间关于对象类型的文章后,我得出了上面的代码,并想分享它。但是,使用 soly 可以回答这个问题。inherits()FALSEres[res$inherits != res$is, ]