object_size类很脆弱

时间:2013-06-25 15:08:14

标签: r oop object

请考虑以下代码段:

> a <- 1:1e7
> b <- 1:1e7
> (sizes <- sapply(c("a","b"),function(n) {
    s <- object.size(get(n))
    cat(n,": ")
    print(s,units="auto")
  }))
a : 38.1 Mb
b : 38.1 Mb
       a        b 
40000040 40000040
> class(sizes)
[1] "numeric"
> (s <- sum(sizes))
[1] 80000080
> class(s) <- "object_size"
> s
80000080 bytes
> print(s,units="auto")
76.3 Mb

观察

  1. sapply"object_size"中移除了sizes类,lapply没有,但其结果 - list - 无法传递给{ {1}})。

  2. sum个对象使用"object_size"而不是units="B"打印

  3. 两者似乎都不是最理想的; "auto"的值应打印为

    sizes

    我的问题是:这只是一个错误,还是这种行为背后有一些深层原因?

2 个答案:

答案 0 :(得分:2)

我认为这里没有任何错误。

事情的真相是R对象的类只是一个与其他属性一样的属性,当sapply将结果简化为向量时,所有属性都被剥离。您可以通过执行此操作来解决问题,尽管输出非常难看

> class(sizes) <- "object_size"
> sizes
40000040 bytes40000040 bytes
> sum(sizes)
80000080 bytes

正如您所指出的那样lapply会保留该类(因为它不会简化),如果您想计算结果的总和,您可以调用以下内容。

> (sizes <- lapply(c("a","b"),function(n) {
    s <- object.size(get(n))
    cat(n,": ")
    print(s,units="auto")
  }))
a : 38.1 Mb
b : 38.1 Mb
[[1]]
40000040 bytes

[[2]]
40000040 bytes

> (s <- do.call(sum, sizes))
80000080

sum也剥离了类,因为没有定义名为"sum.object_size"的函数,而是使用.Primitive("sum"),这再次将其简化为数字。你可以超载它,但@Greg Snow使用Reduce的答案更优雅。

> `sum.object_size` <- function(...){
    s <- sum(unlist(list(...)))
    class(s) <- "object_size"
    s
}
> do.call(sum, sizes)
80000080 bytes

print.object_size的默认行为是使用units="b",无论您在sapply来电中设置了什么。如果您想默认以不同方式打印它们,则必须重载print.object_size

> print.object_size <- function(..., units="auto")
    getFromNamespace("print.object_size", "utils")(..., units=units)
> sizes
[[1]]
38.1 Mb

[[2]]
38.1 Mb

编辑:请注意“已承诺评估”错误

考虑以下功能:

f <- function(x=1){
    h <- function(x) x
    h(x=x)
}
g <- function(x=1){
    h <- function(x=x) x
    h()
}

f将在x的环境中搜索h(x=x)中的f时无问题地运行。另一方面,g会导致错误,因为x中的h()h的环境中搜索,但未定义。{/ p>

答案 1 :(得分:2)

如果要将列表的元素添加在一起,请考虑使用Reduce函数。它将二元运算符(在本例中为+)应用于向量或列表。 +运算符不会删除类和sapplysum等其他属性:

> a <- 1:1e7
> b <- 1:1e7
> (sizes <- lapply(c("a","b"),function(n) {
+ s <- object.size(get(n))
+     cat(n,": ")
+     print(s,units="auto")
+   }))
a : 38.1 Mb
b : 38.1 Mb
[[1]]
40000040 bytes

[[2]]
40000040 bytes

> 
> Reduce('+', sizes)
80000080 bytes
> print(.Last.value, units='auto')
76.3 Mb