Xác định tên hàm trong hàm đó


15

Làm cách nào tôi có thể nhận được tên của hàm trong hàm không ẩn danh đó? bên dưới tôi giả sử có một chức năng hoặc quy trình để thực hiện điều này được gọi magical_r_function()và kết quả đầu ra dự kiến ​​sẽ là gì.

my_fun <- function(){
      magical_r_function()
}
my_fun()
## [1] "my_fun"


foo_bar <- function(){
      magical_r_function()
}
foo_bar()
## [1] "foo_bar"

ballyhoo <- function(){
    foo_bar()
}
ballyhoo()
## [1] "foo_bar"

tom_foolery <- foo_bar
tom_foolery()
## [1] "tom_foolery"

Câu trả lời:


18
as.character(match.call()[[1]])

Bản giới thiệu:

my_fun <- function(){
  as.character(match.call()[[1]])
}
my_fun()
# [1] "my_fun"
foo_bar <- function(){
  as.character(match.call()[[1]])
}
foo_bar()
# [1] "foo_bar"
ballyhoo <- function(){
  foo_bar()
}
ballyhoo()
# [1] "foo_bar"
tom_foolery <- foo_bar
tom_foolery()
# [1] "tom_foolery"

Tyler, tôi chắc chắn không bận tâm (và GG cũng tốt), nhưng tiêu chí của bạn để chọn câu trả lời là gì?
r2evans

Câu hỏi hay. Cả hai sự lựa chọn tuyệt vời. Cả hai dường như làm việc như nhau trong các thử nghiệm của tôi. GG's cung cấp thêm một chút chi tiết. Đó là khó khăn để quyết định.
Tyler Rinker

Khi kiểm tra kỹ hơn điều kiện cuối cùng của việc gán một hàm cho một tên mới, thì điều này sẽ phù hợp hơn với yêu cầu ban đầu.
Tyler Rinker

Xin đừng thay đổi chỉ trên nhận xét của tôi! Tôi không khao khát và cần đại diện (mặc dù bạn sẽ có nhiều hơn một chút so với tôi). Không, tôi chỉ tò mò. Tôi nghĩ cả hai match.callsys.calllà các hàm cơ sở hợp lệ với rất ít sự khác biệt về "hiệu ứng" và "yêu cầu". Vì vậy, tôi đã tò mò để hiểu rằng bạn có thể thích cái này hơn cái kia.
r2evans

12

Hãy thử sys.call(0)nếu một đầu ra đối tượng cuộc gọi là ok hoặc depely nếu bạn chỉ muốn tên như một chuỗi ký tự. Dưới đây là một vài thử nghiệm về điều này. sys.call trả về cả tên và đối số và [[1]] chỉ chọn ra tên.

my_fun <- function() deparse(sys.call(0)[[1]])

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

Tên hàm

Lưu ý rằng các hàm không thực sự có tên. Những gì chúng ta coi là tên hàm thực sự chỉ là các biến giữ hàm và không phải là một phần của chính hàm đó. Một hàm bao gồm các đối số, phần thân và một môi trường - không có tên hàm trong số các thành phần đó.

Chức năng ẩn danh

Hơn nữa, người ta có thể có các chức năng ẩn danh và chúng có thể trả về kết quả lạ khi được sử dụng với ở trên.

sapply(1:3, function(x) deparse(sys.call(0)[[1]]))
## [1] "FUN" "FUN" "FUN"

Trường hợp cạnh

Có tồn tại một số tình huống, đặc biệt liên quan đến các hàm ẩn danh, nơi deparsesẽ trả về nhiều hơn một phần tử, vì vậy nếu bạn muốn bao gồm các trường hợp cạnh như vậy, hãy sử dụng đối số nlines = 1 để làm mờ hoặc sử dụng từ chối (...) [[1]] hoặc như được đề cập bởi @Konrad Rudolph bằng cách sử dụng depzzy1 trong R 4.0.0.

Map(function(x) deparse(sys.call(0)[[1]], nlines = 1), 1:2)
## [[1]]
## [1] "function (x) "
## 
## [[2]]
## [1] "function (x) "

Map(function(x) deparse(sys.call(0)[[1]]), 1:2)  # without nlines=1
## [[1]]
## [1] "function (x) "             "deparse(sys.call(0)[[1]])"
##
## [[2]]
## [1] "function (x) "             "deparse(sys.call(0)[[1]])"

Khác

Nhớ lại . Nếu lý do bạn muốn tên hàm là gọi đệ quy hàm thì sử dụng Recall()thay thế. Từ tệp trợ giúp:

fib <- function(n)
   if(n<=2) { if(n>=0) 1 else 0 } else Recall(n-1) + Recall(n-2)
fib(4)
## [1] 3

cảnh báo và dừng Cả hai đều phát hành tên của hàm cùng với bất kỳ đối số nào được truyền cho chúng để không cần lấy tên hàm hiện tại.

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X

2
Trường hợp cạnh của bạn được giải quyết một cách tao nhã trong R 4.0 thông qua việc giới thiệu deparse1chức năng. Tôi đoán chúng ta nên bắt đầu sử dụng nó thay vì deparsetheo mặc định, một khi việc áp dụng đủ cao.
Konrad Rudolph

+1 cho Recall, điều mà tôi cảm thấy là điều OP thực sự cần. Tuy nhiên, ví dụ về chuỗi Fibonacci của bạn không thực sự tốt: nó có vấn đề là bạn thường lặp lại các cuộc gọi: for fib(10), fib(8)được gọi tổng cộng 2 lần (một lần fib(10)trực tiếp, một lần bởi fib(9)), fib(7)được gọi 3 lần, fib(6)được gọi 5 lần. Thấy nơi đang tới không?
Emil Bode

@Emil, Điều này ngay từ trang Trợ giúp Nhớ lại (như đã nêu trong câu trả lời) vì vậy nó chắc chắn minh họa điểm này. Nếu bạn không thích nó với lý do khác, bạn có thể khiếu nại với các nhà phát triển R.
G. Grothendieck

5

Chúng tôi cũng có thể sử dụng

my_fun <- function(){
  as.character(as.list(sys.calls()[[1]])[[1]])
 }

my_fun()
#[1] "my_fun"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.