【问题标题】:Forcing a package's function to use user-provided function强制包的功能使用用户提供的功能
【发布时间】:2012-05-27 07:57:39
【问题描述】:

我遇到了MNP 包的问题,​​我发现这是对deparse 的不幸调用(其最大宽度限制为500 个字符)。

背景(如果您觉得无聊,可以轻松跳过)

因为mnp 使用了一些特殊的语法来允许不同的选择集(您在公式定义中包括cbind(choiceA,choiceB,...)),所以当model.matrix.default 调用@987654326 时,我的公式调用的左侧是1700 个左右的字符@ 在上面。由于deparse 最多支持500 个字符的width.cutoff,因此model.matrix.default 中的sapply(attr(t, "variables"), deparse, width.cutoff = 500)[-1L] 行作为其第一个元素:

[1] "cbind(plan1, plan2, plan3, plan4, plan5, plan6, plan7, plan8, plan9, plan10, plan11, plan12, plan13, plan14, plan15, plan16, plan17, plan18, plan19, plan20, plan21, plan22, plan23, plan24, plan25, plan26, plan27, plan28, plan29, plan30, plan31, plan32, plan33, plan34, plan35, plan36, plan37, plan38, plan39, plan40, plan41, plan42, plan43, plan44, plan45, plan46, plan47, plan48, plan49, plan50, plan51, plan52, plan53, plan54, plan55, plan56, plan57, plan58, plan59, plan60, plan61, plan62, plan63, "       
[2] "    plan64, plan65, plan66, plan67, plan68, plan69, plan70, plan71, plan72, plan73, plan74, plan75, plan76, plan77, plan78, plan79, plan80, plan81, plan82, plan83, plan84, plan85, plan86, plan87, plan88, plan89, plan90, plan91, plan92, plan93, plan94, plan95, plan96, plan97, plan98, plan99, plan100, plan101, plan102, plan103, plan104, plan105, plan106, plan107, plan108, plan109, plan110, plan111, plan112, plan113, plan114, plan115, plan116, plan117, plan118, plan119, plan120, plan121, plan122, plan123, "
[3] "    plan124, plan125, plan126, plan127, plan128, plan129, plan130, plan131, plan132, plan133, plan134, plan135, plan136, plan137, plan138, plan139, plan140, plan141, plan142, plan143, plan144, plan145, plan146, plan147, plan148, plan149, plan150, plan151, plan152, plan153, plan154, plan155, plan156, plan157, plan158, plan159, plan160, plan161, plan162, plan163, plan164, plan165, plan166, plan167, plan168, plan169, plan170, plan171, plan172, plan173, plan174, plan175, plan176, plan177, plan178, plan179, "
[4] "    plan180, plan181, plan182, plan183, plan184, plan185, plan186, plan187, plan188, plan189, plan190, plan191, plan192, plan193, plan194, plan195, plan196, plan197, plan198, plan199, plan200, plan201, plan202, plan203, plan204, plan205, plan206, plan207, plan208, plan209, plan210, plan211, plan212, plan213, plan214, plan215, plan216, plan217, plan218, plan219, plan220, plan221, plan222, plan223, plan224, plan225, plan226, plan227, plan228, plan229, plan230, plan231, plan232, plan233, plan234, plan235, "
[5] "    plan236, plan237, plan238, plan239, plan240, plan241, plan242, plan243, plan244, plan245, plan246, plan247, plan248, plan249, plan250, plan251, plan252, plan253, plan254, plan255, plan256, plan257, plan258, plan259, plan260, plan261, plan262, plan263, plan264, plan265, plan266, plan267, plan268, plan269, plan270, plan271, plan272, plan273, plan274, plan275, plan276, plan277, plan278, plan279, plan280, plan281, plan282, plan283, plan284, plan285, plan286, plan287, plan288, plan289, plan290, plan291, "
[6] "    plan292, plan293, plan294, plan295, plan296, plan297, plan298, plan299, plan300, plan301, plan302, plan303, plan304, plan305, plan306, plan307, plan308, plan309, plan310, plan311, plan312, plan313)"  

model.matrix.default 对 data.frame 中的变量进行测试时,它会返回错误。

问题

为了解决这个问题,我编写了一个新的deparse 函数:

deparse <- function (expr, width.cutoff = 60L, backtick = mode(expr) %in% 
  c("call", "expression", "(", "function"), control = c("keepInteger", 
                                                        "showAttributes", "keepNA"), nlines = -1L)  {
    ret <- .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control), nlines))
    paste0(ret,collapse="")
  }

但是,当我再次运行 mnp 并单步执行时,它出于相同的原因返回相同的错误(base::deparse 正在运行,而不是我的 deparse)。

这让我有些吃惊,因为我期望这个例子更典型,用户定义的函数暂时覆盖了基函数:

> print <- function() {
+   cat("user-defined print ran\n")
+ }
> print()
user-defined print ran

我意识到解决这个问题的正确方法是重写model.matrix.default,但作为调试工具,我很好奇如何强制它使用我的deparse,以及为什么预期的(由我)行为不是发生在这里。

【问题讨论】:

    标签: debugging r


    【解决方案1】:

    提供函数fixInNamespaceassignInNamespace 以允许编辑现有函数。你可以尝试...但我不会因为与deparse 混在一起看起来太危险了:

     assignInNamespace("deparse", 
                      function (expr, width.cutoff = 60L, backtick = mode(expr) %in% 
                   c("call", "expression", "(", "function"), control = c("keepInteger", 
                   "showAttributes", "keepNA"), nlines = -1L)  {
        ret <- .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control), nlines))
        paste0(ret,collapse="")
                             }   , "base")
    

    帮助页面上显示此类功能的使用受到限制,我不会对此类核心功能可能具有额外的保护层感到惊讶。由于它通过副作用起作用,因此您不需要分配结果。

    【讨论】:

    • ?fixInNamespace 中给出了另一个警告:“它们 [文档中的函数] 不应在生产代码中使用。”
    • 我从@gsk3 的努力中得知这是出于“实验”目的。
    • 谢谢,并已适当注意警告。我可能会更改调用 deparse 而不是 deparse 本身的函数。
    • 由于.Internal(deparse(.)) 的设计,500 个字符的限制仍然可能到位
    • @Dwin 哦,我怀疑是这样。这就是为什么我的代码采用.Internal(deparse(.)) 的输出并在事后修复它的原因。对进一步保护的怀疑是正确的。我既不能修复deparse,也不能修复调用它的model.matrix.default
    【解决方案2】:

    这是带有命名空间的包搜索函数的方式,如Section 1.6, Package Namespaces of Writing R Extensions 中所述

    命名空间在加载后即被密封。密封意味着进口 并且导出无法更改,并且内部变量绑定 无法更改。密封允许更简单的实施策略 对于命名空间机制。密封还允许代码分析和 编译工具准确识别对应的定义 到函数体中的全局变量引用。

    命名空间控制变量使用的搜索策略 包中的功能。如果在本地找不到,R 会搜索包 首先是命名空间,然后是导入,然后是基本命名空间,然后是 正常的搜索路径。

    【讨论】:

    • 我认为发生了类似的事情,所以您已经查明了问题所在。现在如何覆盖? :-)
    • @gsk3:您可能会通过覆盖 deparse 来破坏某些内容,因此我建议您找到要更改的 deparse 调用的确切位置,在该调用之前插入您的函数,然后立即恢复原来的deparse。您也许可以使用fixInNamespace 更改包含您要更改的deparse 调用的函数。
    猜你喜欢
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多