【问题标题】:What does the dot mean in R – personal preference, naming convention or more?R中的点是什么意思——个人偏好、命名约定或更多?
【发布时间】:2011-11-23 11:56:30
【问题描述】:

我(可能)不是指“所有其他变量”,意思是像 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 功能如此强大,以至于我错过了一个早已完成的技巧。

【问题讨论】:

  • 好问题。此外,在函数名称中使用点(is.naas.data.frame、...)在其他编程语言中并不常见,但我喜欢它。
  • purrr 包 (purrr.tidyverse.org) 现在增加了另一层含义,如 ~ .x+1 == function(x) x+1
  • 如果键盘将_ 键放在一个容易到达的位置(例如,你知道,而不是Shopping 键......),那么这种混乱就可以解决了。

标签: r coding-style naming-conventions plyr


【解决方案1】:

函数名中的点可以表示以下任何一种:

  • 什么都没有
  • S3 方法中方法和类之间的分隔符
  • 隐藏函数名

可能的含义

1。什么都没有

data.frame 中的点不会将dataframe 分开,除了视觉上的区别。

2。 S3方法中方法和类的分离

plot 是通用 S3 方法的一个示例。因此plot.lmplot.glm 是调用plot(lm(...))plot(glm(...)) 时使用的底层函数定义

3。隐藏内部函数

在编写包时,有时在函数名称中使用前导点很有用,因为这些函数在一般视图中有些隐藏。纯粹是包内部的函数有时会使用 this。

在这种情况下,“有些隐藏”只是意味着当您使用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

4。其他可能的原因

在 Hadley 的 包中,他使用约定在函数名称中使用前导点。这是一种尝试并确保在解析变量名称时,值解析为用户变量而不是内部函数变量的机制。


并发症

这种不同用途的混搭可能会导致非常混乱的情况,因为这些不同的用途都可能在同一个函数名中混在一起。

例如,要将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>

【讨论】:

  • “有点隐藏”是什么意思?点不会改变变量范围,是吗?所以它只是隐藏在用户通常不会在变量名开头使用点的意义上,对吧?
  • 但这不是通常带有“范围”的肉。范围通常用于全局/本地(函数、包等),而不仅仅是隐藏在 ls() 中(但仍然可以访问)。
  • 哦,我明白你的意思了。不,x.x 的作用域行为是相同的。它们只是碰巧是不同的变量。
  • 我只在 plyr 中这样做,因为您想区分 plyr 函数的参数和 plyr 正在调用的函数的参数。
  • plyr 还有一个. 函数。 get(".") ; function (..., .env = parent.frame()) { structure(as.list(match.call()[-1]), env = .env, class = "quoted") }
【解决方案2】:

在名称的开头,它的工作方式类似于 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 方法还是名称中的一个点。但是,这是一个非常简单但非常强大的机制。

这三个方面的每一个方面都有很多内容,您不应将我的示例视为良好做法,但它们是基本的区别。

【讨论】:

  • 为什么要隐藏一些不是全局的对象?
  • 您还可以将变量或函数定义为单个点!喜欢.=1.(1)。这真的很奇怪,尤其是在表达式.*.+. :-)
【解决方案3】:

如果用户定义了一个函数 .doSomething 并且懒于指定参数的所有 roxygen 文档,编译包不会产生错误

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 2021-06-02
    • 2020-01-06
    相关资源
    最近更新 更多