【问题标题】:Strange difference between x and get("x")?x 和 get("x") 之间的奇怪区别?
【发布时间】:2011-12-26 00:56:29
【问题描述】:

不知何故,有时,我最终会处于这样的状态:

> x
[1] 1 2 3
> get("x")
Error in get("x") : object 'x' not found
> x
[1] 1 2 3

我无法可靠地复制它。我在 C 代码中可能做错了什么?为什么在提示符下输入x 会找到它,而get("x") 却找不到? xget("x") 内部有什么区别?

非常感谢任何提示。我从 R 2.14.0 开始就看到了这一点,但我的 C 代码也发生了变化。

编辑:可重现的示例

// test.c
#include <R.h>
#include <Rdefines.h> 

SEXP test(SEXP df)
{
    SEXP levels, s;
    int j;

    levels = getAttrib(VECTOR_ELT(df,0), R_LevelsSymbol);
    Rprintf("levels %u, type %d, length %d, truelength %d\n",
             levels,TYPEOF(levels),LENGTH(levels),TRUELENGTH(levels));

    for (j=0; j<length(levels); j++) {
        s = STRING_ELT(levels,j);
        Rprintf("%d %d %s %u %d %d\n", length(levels), TYPEOF(s),
                        CHAR(s), s, LENGTH(s), TRUELENGTH(s));
        SET_TRUELENGTH(s,1);  // clobbers the 65, but why 65 ("A") there?
        Rprintf("%d %d %s %u %d %d\n", length(levels), TYPEOF(s),
                        CHAR(s), s, LENGTH(s), TRUELENGTH(s));
    }
    return(R_NilValue);
}

并运行它:

R --vanilla

system("R CMD SHLIB -otest.so test.c")
dyn.load("test.so")

if (FALSE) A     # needed for error to occur (!)

DF <- data.frame(a = c("A", "Z"), b = 1:4)
print(DF)
.Call("test",DF)
print(DF)

A = data.frame()
for (i in 1:100) {
    cat(i,"")
    assign(paste("v",i,sep=""),i)
    get("A")
}

我得到的输出:

$ R --vanilla    
R version 2.14.0 (2011-10-31)
# [snip header]
> system("R CMD SHLIB -otest.so test.c")
gcc -std=gnu99 -I/usr/share/R/include      -fpic  -std=c99 -O6 -Wall -Wno-unused -pedantic -c test.c -o test.o
gcc -std=gnu99 -shared -o test.so test.o -otest.so -L/usr/lib/R/lib -lR
> dyn.load("test.so")
> 
> if (FALSE) A     # needed for error to occur (!)
> 
> DF <- data.frame(a = c("A", "Z"), b = 1:4)
> print(DF)
  a b
1 A 1
2 Z 2
3 A 3
4 Z 4
> .Call("test",DF)
levels 151395176, type 16, length 2, truelength 0
2 9 A 149596512 1 65   # why this 65 here?
2 9 A 149596512 1 1
2 9 Z 149596320 1 0
2 9 Z 149596320 1 1
NULL
> print(DF)
  a b
1 A 1
2 Z 2
3 A 3
4 Z 4
> 
> A = data.frame()
> for (i in 1:100) {
+     cat(i,"")
+     assign(paste("v",i,sep=""),i)
+     get("A")
+ }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Error in get("A") : object 'A' not found
> 
> sessionInfo()
R version 2.14.0 (2011-10-31)
Platform: i686-pc-linux-gnu (32-bit)

locale:
 [1] LC_CTYPE=en_GB.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_GB.UTF-8        LC_COLLATE=en_GB.UTF-8    
 [5] LC_MONETARY=en_GB.UTF-8    LC_MESSAGES=en_GB.UTF-8   
 [7] LC_PAPER=C                 LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     
> 

有什么想法吗?如果 if (FALSE) A 行被注释掉,那么它工作正常。对于重复测试,R 必须每次都从新开始。

【问题讨论】:

  • 您能否详细说明my C code has also been changing too。我不熟悉 C,但您绝对应该发布 C 代码,并等待@Dirk Eddelbuettel 出现。顺便说一句,我无法复制这种行为。
  • 但公开您的代码更为重要。 =)
  • @aL3xa 在这种情况下不是。我是data.table 包的合著者 - 我需要向您展示如何加载它并在开发模式(开发版本)下运行它,然后以特定方式运行它,即使这样对我来说是不可复制的。在问题中,我已经说过我无法复制。这是一个关于在提示符下键入x 和使用get 之间区别的一般问题。好吗?
  • 可能是环境问题? find("x") 给了什么?
  • @James。你好。 find() 找到它,objects() 列出它,所以它似乎在 .GlobalEnv 中,但 get() 不这么认为。

标签: r


【解决方案1】:

这确实是我的 C 代码。我知道 TRUELENGTH 有时被 R 使用,但我没有想到 CHARSXP。当变量名与某个字符值相同时,R 使用 CHARSXP 的 TRUELENGTH 来保存内部散列值,参见 main/envir.c。我在 CHARSXP 上的 SET_TRUELENGTH 正在破坏哈希。感谢 Simon Urbanek 对此的解释,并感谢 cmets 中的所有提示和想法。

演示:

$ R --vanilla
R version 2.14.0 (2011-10-31)

> system("R CMD SHLIB -otest.so test.c")
> dyn.load("test.so")
> truelength = function(x)invisible(.Call("truelength",x))
> 
> truelength("A")
'A' has length 1 and truelength 0
> truelength("ABC")
'ABC' has length 3 and truelength 0
> A=123
> truelength("A")
'A' has length 1 and truelength 65    # 65 is the HASHPRI, for bound variable A
> truelength("ABC")
'ABC' has length 3 and truelength 0    # no variable ABC so truelength unused
> ABC=456
> truelength("ABC")
'ABC' has length 3 and truelength 17763   # now ABC symbol is bound
> 
> foo = 7
> truelength("foo")               
'foo' has length 3 and truelength 27999   # bound
> truelength("bar")               
'bar' has length 3 and truelength 0       # not bound
> .Internal(inspect("foo"))
@876eb08 16 STRSXP g0c1 [NAM(2)] (len=1, tl=0)   # tl=0 of STRSXP vector
  @81759e8 09 CHARSXP g0c1 [gp=0x21] "foo"       # tl of CHARSXP not shown by inspect

查看 CHARSXP TRUELENGTH 的 C 代码在哪里:

// test.c
#include <R.h>
#include <Rdefines.h> 

SEXP truelength(SEXP v)
{
    SEXP s = STRING_ELT(v,0);
    Rprintf("'%s' has length %d and truelength %d\n",
                  CHAR(s), LENGTH(s), TRUELENGTH(s));
    return(R_NilValue);
}

【讨论】:

  • 很高兴知道您已经确定了它!
【解决方案2】:

评论流非常接近问题,这似乎很难/不可能重现:

R> x <- 1L:3L
R> x
[1] 1 2 3
R> get("x")
[1] 1 2 3
R> matt <- function() { y <- 7L:9L; get("y") }
R> matt()
[1] 7 8 9
R>

同样通过 littler:

edd@max:~$ r -e 'x <- 1L:3L; print(get("x"))'
[1] 1 2 3
edd@max:~$

我们需要看到一个可重现的例子。如果它只命中您的系统,尤其是在您的data.table 已加载之后,那么您必须查看那里。不知何故,“封闭框架中的查找符号”逻辑似乎被击中了。

【讨论】:

  • 是的,它可能与正在开发的 data.table 有关。我一直在看它;)但您有时知道它在 C 级别的情况。查找或知道在哪里查找并不总是那么容易。查看 R 的提交日志,我看到 .GlobalEnv 现在已被散列(截至 2011 年 5 月),不确定该更改进入了哪个版本的 R。随后的提交与 R_UnboundValue 有关。那么哈希值是否可以存在,但它不会以某种方式被绑定,这就是xget("x") 之间的区别?如果我能确定这个对象出了什么问题,我也许可以弄清楚是什么原因造成的。
  • 用 setActiveBindings 创建的 x 怎么样?
  • @hadley 刚刚看到你的评论。谢谢,也许。我还没玩过 setActiveBindings。
  • @Dirk 现在添加了复制示例。可能过于本地化,更适合 r-devel?
  • 看到你的更新但还没有时间玩。是的,r-devel 似乎是最好的主意。
猜你喜欢
  • 1970-01-01
  • 2013-06-14
  • 2011-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-20
  • 1970-01-01
相关资源
最近更新 更多