我经常看到新手R程序员的问题,他们习惯于assign创建多个对象,然后在尝试为后续任务操作这些对象时遇到麻烦(最近的一个例子).
assign吸引新手用户,因为它具有动态属性(以编程方式创建变量名称,除了变量的值),并且似乎模仿了全局赋值的一些属性.它的直接名称也使它可能出现在各种问题类型的搜索中.
当然,更有经验的R程序员开始意识到assign创建难以阅读的代码,易于维护的代码,以及通过在高功能R语言中坚决避免的副作用类型的行为.
我在SO最初使用的所有问题上看到的每个问题assign最终在正确使用命名向量,列表或数据帧方面有更好的选择.生成的代码更易于遵循,更易于更改,并且通常性能更高.
所有这一切都是说,很容易找到为什么assign不好的例子.我的问题是:在什么情况下使用assign适当的,首选的或唯一的解决方案?
如果您正在构建一个程序来介导与用户的对话,其中要求用户输入任意对象名称(在特定名称空间中列出的未加引号字符串的特定R意义上),您可以考虑使用assign.
该选项assign以特定的环境也可能具有价值.注意它是如何在ecdf函数中使用的:
ecdf
#----screen output----
function (x)
{
x <- sort(x)
n <- length(x)
if (n < 1)
stop("'x' must have 1 or more non-missing values")
vals <- unique(x)
rval <- approxfun(vals, cumsum(tabulate(match(x, vals)))/n,
method = "constant", yleft = 0, yright = 1, f = 0, ties = "ordered")
class(rval) <- c("ecdf", "stepfun", class(rval))
assign("nobs", n, envir = environment(rval))
attr(rval, "call") <- sys.call()
rval
}
<bytecode: 0x7c77cc0>
<environment: namespace:stats>
Run Code Online (Sandbox Code Playgroud)
该ecdf函数获取数据并返回另一个函数.大多数函数是使用C调用构建的approxfun,但作为最后一个特性,ecdf函数会向返回值的环境添加一个元素(这是另一个函数.)
我相信你可以找到其他实例,其中assign包括base和stats包的R代码.这些可以说是"R Core Certified ^({TM}}""适当"用途的例子.
当我按照自己的建议时,我从bash操作得到了这个:
$ cd '/home/david/Downloads/R-3.5.2/src/library/base/R/'
$ grep -R "assign"
# --- results with a recent download of the R sources -----
userhooks.R: assign(hookName, new, envir = .userHooksEnv, inherits = FALSE)
datetime.R: cacheIt <- function(tz) assign(".sys.timezone", tz, baseenv())
autoload.R: assign(".Autoloaded", c(package, .Autoloaded), envir =.AutoloadEnv)
lazyload.R: ## set <- function (x, value, env) .Internal(assign(x, value, env, FALSE))
delay.R: function(x, value, eval.env=parent.frame(1), assign.env=parent.frame(1))
delay.R: .Internal(delayedAssign(x, substitute(value), eval.env, assign.env))
assign.R:# File src/library/base/R/assign.R
assign.R:assign <-
assign.R: .Internal(assign(x, value, envir, inherits))
# stripped out some occurences of "assighnment"
# stripped out the occurrences of "assign" in the namespace functions
zzz.R:assign("%*%", function(x, y) NULL, envir = .ArgsEnv)
zzz.R:assign("...length", function() NULL, envir = .ArgsEnv)
zzz.R:assign("...elt", function(n) NULL, envir = .ArgsEnv)
zzz.R:assign(".C", function(.NAME, ..., NAOK = FALSE, DUP = TRUE, PACKAGE,
zzz.R:assign(".Fortran",
zzz.R:assign(".Call", function(.NAME, ..., PACKAGE) NULL, envir = .ArgsEnv)
zzz.R:assign(".Call.graphics", function(.NAME, ..., PACKAGE) NULL, envir = .ArgsEnv)
zzz.R:assign(".External", function(.NAME, ..., PACKAGE) NULL, envir = .ArgsEnv)
zzz.R:assign(".External2", function(.NAME, ..., PACKAGE) NULL, envir = .ArgsEnv)
zzz.R:assign(".External.graphics", function(.NAME, ..., PACKAGE) NULL,
zzz.R:assign(".Internal", function(call) NULL, envir = .ArgsEnv)
zzz.R:assign(".Primitive", function(name) NULL, envir = .ArgsEnv)
zzz.R:assign(".isMethodsDispatchOn", function(onOff = NULL) NULL, envir = .ArgsEnv)
zzz.R:assign(".primTrace", function(obj) NULL, envir = .ArgsEnv)
zzz.R:assign(".primUntrace", function(obj) NULL, envir = .ArgsEnv)
zzz.R:assign(".subset", function(x, ...) NULL, envir = .ArgsEnv)
zzz.R:assign(".subset2", function(x, ...) NULL, envir = .ArgsEnv)
zzz.R:assign("UseMethod", function(generic, object) NULL, envir = .ArgsEnv)
zzz.R:assign("as.call", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("attr", function(x, which, exact = FALSE) NULL, envir = .ArgsEnv)
zzz.R:assign("attr<-", function(x, which, value) NULL, envir = .ArgsEnv)
zzz.R:assign("attributes", function(obj) NULL, envir = .ArgsEnv)
zzz.R:assign("attributes<-", function(obj, value) NULL, envir = .ArgsEnv)
zzz.R:assign("baseenv", function() NULL, envir = .ArgsEnv)
zzz.R:assign("browser",
zzz.R:assign("call", function(name, ...) NULL, envir = .ArgsEnv)
zzz.R:assign("class", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("class<-", function(x, value) NULL, envir = .ArgsEnv)
zzz.R:assign(".cache_class", function(class, extends) NULL, envir = .ArgsEnv)
zzz.R:assign("emptyenv", function() NULL, envir = .ArgsEnv)
zzz.R:assign("enc2native", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("enc2utf8", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("environment<-", function(fun, value) NULL, envir = .ArgsEnv)
zzz.R:assign("expression", function(...) NULL, envir = .ArgsEnv)
zzz.R:assign("forceAndCall", function(n, FUN, ...) NULL, envir = .ArgsEnv)
zzz.R:assign("gc.time", function(on = TRUE) NULL, envir = .ArgsEnv)
zzz.R:assign("globalenv", function() NULL, envir = .ArgsEnv)
zzz.R:assign("interactive", function() NULL, envir = .ArgsEnv)
zzz.R:assign("invisible", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.atomic", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.call", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.character", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.complex", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.double", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.environment", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.expression", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.function", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.integer", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.language", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.list", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.logical", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.name", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.null", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.object", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.pairlist", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.raw", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.recursive", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.single", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("is.symbol", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("isS4", function(object) NULL, envir = .ArgsEnv)
zzz.R:assign("list", function(...) NULL, envir = .ArgsEnv)
zzz.R:assign("lazyLoadDBfetch", function(key, file, compressed, hook) NULL,
zzz.R:assign("missing", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("nargs", function() NULL, envir = .ArgsEnv)
zzz.R:assign("nzchar", function(x, keepNA=FALSE) NULL, envir = .ArgsEnv)
zzz.R:assign("oldClass", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("oldClass<-", function(x, value) NULL, envir = .ArgsEnv)
zzz.R:assign("on.exit", function(expr = NULL, add = FALSE, after = TRUE) NULL, envir = .ArgsEnv)
zzz.R:assign("pos.to.env", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("proc.time", function() NULL, envir = .ArgsEnv)
zzz.R:assign("quote", function(expr) NULL, envir = .ArgsEnv)
zzz.R:assign("retracemem", function(x, previous = NULL) NULL, envir = .ArgsEnv)
zzz.R:assign("seq_along", function(along.with) NULL, envir = .ArgsEnv)
zzz.R:assign("seq_len", function(length.out) NULL, envir = .ArgsEnv)
zzz.R:assign("standardGeneric", function(f, fdef) NULL, envir = .ArgsEnv)
zzz.R:assign("storage.mode<-", function(x, value) NULL, envir = .ArgsEnv)
zzz.R:assign("substitute", function(expr, env) NULL, envir = .ArgsEnv)
zzz.R:assign("switch", function(EXPR, ...) NULL, envir = .ArgsEnv)
zzz.R:assign("tracemem", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("unclass", function(x) NULL, envir = .ArgsEnv)
zzz.R:assign("untracemem", function(x) NULL, envir = .ArgsEnv)
zzz.R: assign(f, fx, envir = env) # grep fails to include the names of these
zzz.R: assign(f, fx, envir = env)
zzz.R: assign(f, fx, envir = env)
zzz.R: assign(f, fx, envir = env)
zzz.R: assign(f, fx, envir = env)
zzz.R: assign("anyNA", fx, envir = env)
zzz.R:assign("!", function(x) UseMethod("!"), envir = .GenericArgsEnv)
zzz.R:assign("as.character", function(x, ...) UseMethod("as.character"),
zzz.R:assign("as.complex", function(x, ...) UseMethod("as.complex"),
zzz.R:assign("as.double", function(x, ...) UseMethod("as.double"),
zzz.R:assign("as.integer", function(x, ...) UseMethod("as.integer"),
zzz.R:assign("as.logical", function(x, ...) UseMethod("as.logical"),
zzz.R:#assign("as.raw", function(x) UseMethod("as.raw"), envir = .GenericArgsEnv)
zzz.R:## assign("c", function(..., recursive = FALSE, use.names = TRUE) UseMethod("c"),
zzz.R:assign("c", function(...) UseMethod("c"),
zzz.R:#assign("dimnames", function(x) UseMethod("dimnames"), envir = .GenericArgsEnv)
zzz.R:assign("dim<-", function(x, value) UseMethod("dim<-"), envir = .GenericArgsEnv)
zzz.R:assign("dimnames<-", function(x, value) UseMethod("dimnames<-"),
zzz.R:assign("length<-", function(x, value) UseMethod("length<-"),
zzz.R:assign("levels<-", function(x, value) UseMethod("levels<-"),
zzz.R:assign("log", function(x, base=exp(1)) UseMethod("log"),
zzz.R:assign("names<-", function(x, value) UseMethod("names<-"),
zzz.R:assign("rep", function(x, ...) UseMethod("rep"), envir = .GenericArgsEnv)
zzz.R:assign("round", function(x, digits=0) UseMethod("round"),
zzz.R:assign("seq.int", function(from, to, by, length.out, along.with, ...)
zzz.R:assign("signif", function(x, digits=6) UseMethod("signif"),
zzz.R:assign("trunc", function(x, ...) UseMethod("trunc"), envir = .GenericArgsEnv)
zzz.R:#assign("xtfrm", function(x) UseMethod("xtfrm"), envir = .GenericArgsEnv)
zzz.R:assign("as.numeric", get("as.double", envir = .GenericArgsEnv),
Run Code Online (Sandbox Code Playgroud)