【问题标题】:Order of messages to console within functions when piped管道时在函数内控制台的消息顺序
【发布时间】:2021-06-25 13:16:06
【问题描述】:

编辑:我不是故意粗鲁,所以只是没有接受我的问候..

你好,

为了跟踪某些函数的处理,我想在函数启动和完成时在控制台中打印消息。

我是tidyverse 和管道操作员%>% 的忠实粉丝。但是我刚刚发现函数开头的消息打印顺序错误,而结尾的消息顺序正确。

有人知道为什么或如何解决这个问题吗?

这是一些代码:

library(tidyverse)
testdata <- data.frame(a=c(3,5,7,1,2),b=c(2,5,6,3,9))

foo_1 <- function(DF){
  message("Hello 1")
  Obj <- DF %>% 
    mutate(Test_1=a*b)
  message("Bye 1")
  return(Obj)
} 

foo_2 <- function(DF){
  message("Hello 2")
  
  Obj <- DF %>% 
    mutate(Test_2=Test_1*2)
  message("Bye 2")
  return(Obj)
}

foo_3 <- function(DF){
  message("Hello 3")
  Obj <- DF %>% 
    mutate(Test_3=Test_2/a)
  
  message("Bye 3")
  return(Obj)
}

testdata %>% 
  foo_1() %>% 
  foo_2() %>% 
  foo_3()

控制台打印的结果是:

Hello 3
Hello 2
Hello 1
Bye 1
Bye 2
Bye 3
  a b Test_1 Test_2 Test_3
1 3 2      6     12      4
2 5 5     25     50     10
3 7 6     42     84     12
4 1 3      3      6      6
5 2 9     18     36     18

我期望的是以下消息顺序:

Hello 1
Bye 1
Hello 2
Bye 2
Hello 3
Bye 3
  a b Test_1 Test_2 Test_3
1 3 2      6     12      4
2 5 5     25     50     10
3 7 6     42     84     12
4 1 3      3      6      6
5 2 9     18     36     18

【问题讨论】:

  • 这不是管道问题。试试foo_3(foo_2(foo_1(testdata)))

标签: r pipe tidyverse


【解决方案1】:

1) flush.console 使用 flush.console 强制显示此时排队的消息。

testdata %>% 
  foo_1() %>% 
  { flush.console(); foo_2(.) } %>% 
  { flush.console(); foo_3(.) }

给出这个输出:

Hello 1
Bye 1
Hello 2
Bye 2
Hello 3
Bye 3
  a b Test_1 Test_2 Test_3
1 3 2      6     12      4
2 5 5     25     50     10
3 7 6     42     84     12
4 1 3      3      6      6
5 2 9     18     36     18

2) Bizarro pipe 另一种方法是使用Bizarro pipe,这是一种巧妙的基本语法,看起来像管道。

testdata ->.;
  foo_1(.) ->.;
  foo_2(.) ->.;
  foo_3(.)

给予:

Hello 1
Bye 1
Hello 2
Bye 2
Hello 3
Bye 3
  a b Test_1 Test_2 Test_3
1 3 2      6     12      4
2 5 5     25     50     10
3 7 6     42     84     12
4 1 3      3      6      6
5 2 9     18     36     18

3) force 强制对三个函数中的参数求值。

foo_1 <- function(DF){
  force(DF) #######
  message("Hello 1")
  Obj <- DF %>% 
    mutate(Test_1=a*b)
  message("Bye 1")
  return(Obj)
} 

foo_2 <- function(DF){
  force(DF) #######
  message("Hello 2")
  Obj <- DF %>% 
    mutate(Test_2=Test_1*2)
  message("Bye 2")
  return(Obj)
}

foo_3 <- function(DF){
  force(DF) #######
  message("Hello 3")
  Obj <- DF %>% 
    mutate(Test_3=Test_2/a)
  
  message("Bye 3")
  return(Obj)
}

testdata %>% 
  foo_1 %>%
  foo_2 %>%
  foo_3

给予:

Hello 1
Bye 1
Hello 2
Bye 2
Hello 3
Bye 3
  a b Test_1 Test_2 Test_3
1 3 2      6     12      4
2 5 5     25     50     10
3 7 6     42     84     12
4 1 3      3      6      6
5 2 9     18     36     18

4) pipe_eager_lexical magrittr 开发人员 Lionel 向我指出 magrittr 有一个渴望管道,但没有将其分配给 %..% 运算符;但是,我们可以很容易地做到这一点。

library(magrittr)

`%>e%` <- pipe_eager_lexical  # eager pipe

testdata %>e% 
  foo_1() %>e% 
  foo_2() %>e% 
  foo_3()

给予:

Hello 1
Bye 1
Hello 2
Bye 2
Hello 3
Bye 3
  a b Test_1 Test_2 Test_3
1 3 2      6     12      4
2 5 5     25     50     10
3 7 6     42     84     12
4 1 3      3      6      6
5 2 9     18     36     18

【讨论】:

  • 非常感谢这些不同的方法。使用force() 有什么缺点吗?
  • 一个缺点是需要修改功能。
  • 没问题,都是我自己写的用户函数。
  • 已添加 (4) 个。
  • Lionel 表示他愿意在 magrittr 管道中预定义一个运算符,以便在有兴趣的情况下进行热切评估,所以如果你想要这个,那么请在github.com/tidyverse/magrittr/issues/247
【解决方案2】:

您将消息从各个函数中移出,并在您放置消息的位置围绕它们生成一个包装器:

使用一些 sudo-ish 代码:

my_wrapper <- function(){
message('h1')
foo_1()
message('b1')
message('h2')
...
message('b3')
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-05
    相关资源
    最近更新 更多