我(可能)不在这里指的是“所有其他变量”,例如var1~.
。我再一次指向plyr
,然后查看mlply
,想知道为什么用这样的前导点定义参数:
function (.data, .fun = NULL, ..., .expand = TRUE, .progress = "none",
.parallel = FALSE)
{
if (is.matrix(.data) & !is.list(.data))
.data <- .matrix_to_df(.data)
f <- splat(.fun)
alply(.data = .data, .margins = 1, .fun = f, ..., .expand = .expand,
.progress = .progress, .parallel = .parallel)
}
<environment: namespace:plyr>
这有什么用?仅仅是个人喜好,命名约定还是更多? R通常功能如此强大,以至于我错过了一个早已完成的技巧。
函数名称中的点可以表示以下任何一项:
data.frame
中的点除了视觉上没有将data
与frame
分开。
plot
是通用S3方法的一个示例。因此,plot.lm
和plot.glm
是在调用plot(lm(...))
或plot(glm(...))
编写程序包时,有时在函数名称中使用前导点很有用,因为这些函数在一般视图中有些隐藏。纯粹在软件包内部的功能有时会使用此功能。
在这种情况下,“有些隐藏”只是意味着当用ls()
列出对象时,变量(或函数)通常不会显示。要强制ls
显示这些变量,请使用ls(all.names=TRUE)
。通过使用点作为变量的首字母,可以更改变量本身的范围。例如:
x <- 3
.x <- 4
ls()
[1] "x"
ls(all.names=TRUE)
[1] ".x" "x"
x
[1] 3
.x
[1] 4
在Hadley的plyr程序包中,他使用约定在函数名称中使用前导点。这是一种尝试确保在解析变量名时将值解析为用户变量而不是内部函数变量的机制。
这种不同用途的混搭可能导致非常混乱的情况,因为这些不同用途可以在相同的函数名称中混合在一起。
例如,要将data.frame
转换为列表,请使用as.list(..)
as.list(iris)
在这种情况下,as.list
是S3的通用方法,您正在向其传递data.frame
。因此,S3函数称为as.list.data.frame
:
> as.list.data.frame
function (x, ...)
{
x <- unclass(x)
attr(x, "row.names") <- NULL
x
}
<environment: namespace:base>
对于真正引人注目的事物,请加载data.table
包并查看函数as.data.table.data.frame
:
> library(data.table)
> methods(as.data.table)
[1] as.data.table.data.frame* as.data.table.data.table* as.data.table.matrix*
Non-visible functions are asterisked
> data.table:::as.data.table.data.frame
function (x, keep.rownames = FALSE)
{
if (keep.rownames)
return(data.table(rn = rownames(x), x, keep.rownames = FALSE))
attr(x, "row.names") = .set_row_names(nrow(x))
class(x) = c("data.table", "data.frame")
x
}
<environment: namespace:data.table>
名称的开头类似于UNIX文件名约定,默认情况下将对象隐藏。
ls()
character(0)
.a <- 1
ls()
character(0)
ls(all.names = TRUE)
[1] ".a"
它可以只是一个没有特殊含义的令牌,它所做的不过是任何其他允许的令牌。
my.var <- 1
my_var <- 1
myVar <- 1
用于S3方法分派。因此,如果我定义简单的类“ myClass”并使用该类属性创建对象,则诸如print()之类的通用函数将自动分派到我的特定打印方法。
myvar <- 1
print(myvar)
class(myvar) <- c("myClass", class(myvar))
print.myClass <- function(x, ...) {
print(paste("a special message for myClass objects, this one has length", length(x)))
return(invisible(NULL))
}
print(myvar)
S3的语法有歧义,因为您无法从函数名称中分辨出它是S3方法还是名称中的点。但是,这是一个非常简单的机制,功能非常强大。
这三个方面还有很多,您不应该将我的示例作为好的实践,但是它们是基本的区别。
如果用户定义了一个函数.doSomething,并且懒于为参数指定所有roxygen文档,它将不会在编译程序包时产生错误