dhe*_*rsz 6 printing methods copy r
我正在 R 中创建一个自定义 S3 对象,但是当我打印它时,属性也会被打印。例如:
x <- 1:3
x <- structure(x, class = "myclass")
print(x)
#> [1] 1 2 3
#> attr(,"class")
#> [1] "myclass"
Run Code Online (Sandbox Code Playgroud)
公平地说,我还没有添加print方法。SO 和其他地方的许多答案建议从对象中删除属性,然后打印它,如下所示(也以不可见的方式返回对象以保持原始print属性):
x <- 1:3
x <- structure(x, class = "myclass")
print.myclass <- function(x, ...) {
print(unclass(x), ...)
return(invisible(x))
}
print(x)
#> [1] 1 2 3
Run Code Online (Sandbox Code Playgroud)
然而,这种方法会创建 的副本x,而我不希望这样。我们可以看到tracemem():
x <- 1:3
x <- structure(x, class = "myclass")
tracemem(x)
#> [1] "<0x558e1a9adcc8>"
print.myclass <- function(x, ...) {
print(unclass(x), ...)
return(invisible(x))
}
print(x)
#> tracemem[0x558e1a9adcc8 -> 0x558e1aa63918]: print print.myclass print
#> [1] 1 2 3
Run Code Online (Sandbox Code Playgroud)
原件print不会创建以下副本x:
x <- 1:3
x <- structure(x, class = "myclass")
tracemem(x)
#> [1] "<0x557799ebeb88>"
print(x)
#> [1] 1 2 3
#> attr(,"class")
#> [1] "myclass"
Run Code Online (Sandbox Code Playgroud)
Hadley 在他的《Advanced R》一书中建议,可以使用子集方法NextMethod()来防止创建副本。我花了一些时间思考如何在打印具有属性的 S3 对象时防止创建副本,但我不知道如何做到这一点。
事实上,我刚刚测试了打印 atibble并且还创建了一个副本:
z <- tibble::tibble(x = 1, y = 2)
tracemem(z)
#> [1] "<0x55e2aa368c48>"
print(z)
#> tracemem[0x55e2aa368c48 -> 0x55e2aa339e48]: lapply tbl_subset_row [.tbl_df [ do.call head.data.frame head as.data.frame tbl_format_setup.tbl tbl_format_setup_ tbl_format_setup format.tbl format writeLines print.tbl
#> # A tibble: 1 x 2
#> x y
#> <dbl> <dbl>
#> 1 1 2
Run Code Online (Sandbox Code Playgroud)
但 adata.table没有:
z <- data.table::data.table(x = 1, y = 2)
tracemem(z)
#> [1] "<0x55d64b2bd310>"
print(z)
#> x y
#> 1: 1 2
Run Code Online (Sandbox Code Playgroud)
所以我想这个问题是可以解决的,但我还没弄清楚如何......
编辑:
好的,我做了一些阅读print.data.frame,它通过将 转换data.frame为 amatrix然后打印这个矩阵来解决这个问题。这是一个非常聪明的解决方案,我猜data.table使用了类似的东西。
然而,更一般地说,这对于某些其他类型的对象(例如,无法格式化为矩阵的对象)不起作用。拿这个:
z <- list(a = data.frame(a = 1, b = 2), b = data.frame(c = 3, d = 4))
z <- structure(z, class = "myotherclass")
tracemem(z)
#> [1] "<0x56298a95fd48>"
print(z)
#> $a
#> a b
#> 1 1 2
#>
#> $b
#> c d
#> 1 3 4
#>
#> attr(,"class")
#> [1] "myotherclass"
print.myotherclass <- function(x, ...) {
print(unclass(x), ...)
return(invisible(x))
}
print(z)
#> tracemem[0x56298a95fd48 -> 0x56298aaa58a8]: print print.myotherclass print
#> $a
#> a b
#> 1 1 2
#>
#> $b
#> c d
#> 1 3 4
Run Code Online (Sandbox Code Playgroud)
在这种情况下你是怎么做的?
print(x[seq_along(x)])在你的打印方法中使用类似的东西怎么样?它避免了看起来的复制,并且属性仍然存在。
z <- list(a = data.frame(a = 1, b = 2), b = data.frame(c = 3, d = 4))
z <- structure(z, class = "myotherclass")
tracemem(z)
print.myotherclass <- function(x, ...) {
print(x[seq_along(x)])
return(invisible(x))
}
y <- print(z)
#> $`a`
#> a b
#> 1 1 2
#>
#> $b
#> c d
#> 1 3 4
attributes(y)
#> $`names`
#> [1] "a" "b"
#>
#> $class
#> [1] "myotherclass"
Run Code Online (Sandbox Code Playgroud)