在R中,具有与基本R函数同名的variables的问题到底是什么?
似乎通常认为使用具有相同名称的基数R中的函数的variables名称是不好的编程习惯。
例如,写下以下内容很诱人:
data <- data.frame(...) df <- data.frame(...)
现在,函数data
加载数据集,而函数df
计算f密度函数。
同样,写这样的文章是很有诱惑力的:
a <- 1 b <- 2 c <- 3
这被认为是不好的forms,因为函数c
将结合它的论点。
但是:在R函数lm
,为了计算线性模型, data
被用作参数。 换句话说, data
在lm
函数中变成一个显式variables。
所以:如果R核心团队可以为variables和函数使用相同的名称,那么我们是不是凡人呢?
答案不是R会混淆。 尝试下面的例子,我明确地分配一个名字为c
的variables。 R不会因为variables和函数之间的差异而感到困惑:
c("A", "B") [1] "A" "B" c <- c("Some text", "Second", "Third") c(1, 3, 5) [1] 1 3 5 c[3] [1] "Third"
问题:具有与基本R函数同名的variables的问题究竟是什么?
真的没有一个。 在寻找函数时,R通常不会search对象(非函数对象):
> mean(1:10) [1] 5.5 > mean <- 1 > mean(1:10) [1] 5.5 > rm(mean) > mean(1:10) [1] 5.5
@Joris和@Sacha所示的例子是糟糕的编码让你失望。 一个更好的书写foo
是:
foo <- function(x, fun) { fun <- match.fun(fun) fun(x) }
当使用时给出:
> foo(1:10, mean) [1] 5.5 > mean <- 1 > foo(1:10, mean) [1] 5.5
在某些情况下,这会把你赶出去,而na.omit
的例子是na.omit
,因为lm()
使用了标准的非标准评估,所以IIRC正在发生。
几个答案还将T
与TRUE
问题与function问题的掩饰混为一谈。 由于T
和TRUE
不是@ Andrie问题范围之外的函数。
问题不在于计算机,而在于用户。 一般来说,代码可能变得很难debugging。 input错误很容易,所以如果你这样做:
c <- c("Some text", "Second", "Third") c[3] c(3)
你得到正确的结果。 但是如果你错过了代码中的某处并键入c(3)
而不是c[3]
,那么发现错误并不会那么容易。
范围界定也会导致非常混乱的错误报告。 采取以下有缺陷的function:
my.foo <- function(x){ if(x) c <- 1 c + 1 } > my.foo(TRUE) [1] 2 > my.foo(FALSE) Error in c + 1 : non-numeric argument to binary operator
用更复杂的function,这可能导致你在一个无处不在的debugging线索。 如果在上面的函数中用c
replacec
,那么错误将会被读为“ object 'x' not found
”。 这将导致更快的编码错误。
接下来,它会导致相当混乱的代码。 像c(c+c(a,b,c))
的代码比c(d+c(a,b,d))
要求大脑更多。 再次,这是一个微不足道的例子,但它可以有所作为。
显然,你也可以得到错误。 当你期望一个function,你不会得到它,这可能会导致另一个恼人的错误:
my.foo <- function(x,fun) fun(x) my.foo(1,sum) [1] 1 my.foo(1,c) Error in my.foo(1, c) : could not find function "fun"
一个更现实(和现实生活)的例子,这可能会导致麻烦:
x <- c(1:10,NA) y <- c(NA,1:10) lm(x~y,na.action=na.omit) # ... correct output ... na.omit <- TRUE lm(x~y,na.action=na.omit) Error in model.frame.default(formula = x ~ y, na.action = na.omit, drop.unused.levels = TRUE) : attempt to apply non-function
如果na.omit <- TRUE
在您的代码中出现50行,请尝试找出这里有什么问题…
在@Andrie的评论之后回答编辑,以包含混淆错误报告的例子
R对此非常强大,但你可以想办法打破它。 例如,考虑这个function:
foo <- function(x,fun) fun(x)
这简单地适用于x
fun
。 不是最好的方式做到这一点,但你可能会遇到这个从某人的脚本左右。 这适用于mean()
:
> foo(1:10,mean) [1] 5.5
但是,如果我分配一个新的价值意味着它打破:
mean <- 1 foo(1:10,mean) Error in foo(1:10, mean) : could not find function "fun"
这很less发生,但可能会发生。 如果同样的事情意味着两件事情,这也是令人困惑的:
mean(mean)
既然使用任何你想要的名字是微不足道的,为什么不使用一个不同的名字,然后基地的Rfunction? 而且,对于一些Rvariables,这变得更加重要。 想想重新分配'+'
function! 另一个很好的例子是T
和F
重新分配,可以打破这么多的脚本。
我认为问题在于人们在全球环境中使用这些function,并且由于某些您不应该得到的意想不到的错误而导致挫败感。 想象一下,你只是运行了一个可重复的例子(可能相当长),覆盖了你在仿真中使用的一个函数,需要很长时间才能到达你想要的地方,然后突然间出现一个有趣的错误。 在closures的环境中使用已经存在的variables函数名称(如函数)在函数closures后被删除,不应该造成伤害。 假设程序员知道这种行为的所有后果。
答案很简单。 那么,那种。
底线是你应该避免混淆。 从技术上讲,没有理由给你的variables专有名称,但它使你的代码更容易阅读。
假设有一行代码包含data()[1]
或类似的代码(这一行可能没有意义,但这只是一个例子):虽然现在你很清楚你正在使用函数数据,一个读者注意到那里有一个data.frame命名的数据,可能会感到困惑。
如果你不是不偏不倚,记住,读者可能在半年左右,试图弄清楚你正在用“旧代码”做什么。
从一个学会使用长variables名称和命名约定的人那里得到它:回报!
我同意@Gavin Simpson和@Nick Sabbe认为没有问题,但这更多的是代码的可读性问题。 因此,生活中的许多事情,这是一个约定和共识的问题。
我认为给出一般build议是一个很好的习惯:不要将你的variables命名为基本的R函数!
这个build议和其他好的build议一样。 例如大家都知道我们不要喝太多的酒,不要吃太多的不健康的食物,但是我们不时会遵循这些build议,在吃太多垃圾食物的时候喝醉了。
这个build议也是一样的。 命名数据参数data
显然是有意义的。 但是,命名数据向量的mean
就不那么有意义了。 虽然可能有这样的情况,即使这似乎是适当的。 但要尽量避免这些情况的清晰。
虽然有些语言可能会允许,但是IF IF THEN THEN ELSE ELSE
人想到其他的话。 总的来说,这被认为是很差的做法。 这并不是说我们不想让你有机会炫耀你对语言的高级知识,总有一天,我们将不得不处理那些代码,而我们只是凡人而已。
因此,如果你感觉到额外的温暖和模糊,那么保存你的编程技巧就不要打破每晚的构build,并给你的variables合理的名字,一致的shell。