is和inherits有什么区别?
is()和inherits()是用于测试对象类型的两个函数。根据给出的答案,我进行了以下操作:
- 创建了不同类型的R对象
- 使用storage.mode()、mode()、typeof()和class()提取了这些对象的类型
- 使用is()、inherits()和is.*()来测试这些对象是否属于返回的类型
以下是上述三个步骤的一个小例子:
# 使用storage.mode()、mode()、typeof()和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" # 使用is、inherits和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
现在我们使用以下代码对一组对象类型进行相同的操作:
# 生成不同类型的对象 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("")$node ) # 提取类型并进行测试 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, ]`就可以回答这个问题。
短版:
大部分情况下使用inherits
,但在处理数字和S4类时要小心。
长版:
从is
帮助页面的“See Also”部分:
inherits对于S4和非S4对象几乎总是等效于is,并且速度稍快。不等价的情况是在具有条件超类的类中,关系中有非平凡的测试(不常见且不建议使用):对于这些情况,is测试关系,但inherits按定义忽略S4对象的条件继承。
从inherits
帮助页面的“Formal Classes”部分:
正式类的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
那么,你能解释一下为什么整数不会“继承”,而浮点数会吗? Rgames> class(1.4) [1] "numeric" Rgames> is.numeric(1.4) [1] TRUE Rgames> inherits(1.4,'numeric') [1] TRUE Rgames> is(1.4,'numeric') [1] TRUE
我认为这可能与数值对象只有一个隐式类有关:从?class
,如果对象没有类属性,则具有隐式类“"matrix"”、“"array"”或“mode(x)”的结果(除了整数向量具有隐式类“"integer"”)。
我可以想象(??)is
关注隐式类而inherits
则不关注...?
我记得听说过一位高级R专家称这为“不幸之处”。
另一个非常关键的区别是is
是methods
包中的函数,默认情况下在运行Rscript
时不加载该包(因为加载速度慢)。相比之下,inherits
来自base
,因此在R脚本程序中可以直接使用。