函数可以访问其名称吗?


25

在C语言中,有magic变量__func__保存当前函数的名称。在Bash中,有一个数组FUNCNAME保存调用堆栈中所有函数的名称!

Emacs Lisp中有类似的东西吗?还是通过任何简单的方法来访问函数的名称?

我在Emacs Lisp手册中没有找到任何答案(有关函数或变量和函数索引以及..的第12章)


2
您实际上需要什么呢?
lunaryorn 2014年

1
这不是一个魔术变量,而是一些编译器插入的预处理器定义。
肖恩·阿雷德

Answers:


6

对于交互式功能(例如命令),可以使用变量this-command或更安全的real-this-command。不同之处在于,编写自己的函数时,可以显式更改的值this-command。通常,这样做是为了玩一些last-command与重复命令有关的技巧。您不应该(不能吗?)使用进行此操作real-this-command。它始终是当前命令的名称。

我不知道非交互功能的等效项。


3
请务必注意,this-command并且一点real-last-command也不喜欢__func__。例如,如果命令A调用命令B进行打印this-command,则命令B 将打印命令A,而不是命令B,这对于功能完全无效。
Jordon Biondo

1
@JordonBiondo同意。我确实注意到它不适用于功能。phs没有提供他的上下文信息,所以我猜想这对于他的应用程序可能已经足够了。您的答案更可靠,没问题。
泰勒(Tyler)2015年

22

更新了扩展时间查找答案:

我在最初的回答中说过,也许有一种方法可以在扩展/编译时而不是运行时执行,以提供更好的性能,今天我在解决这个问题的答案时终于实现了这一点:我如何确定哪个函数是在堆栈中以交互方式调用?

这是产生所有当前回溯帧的函数

(defun call-stack ()
  "Return the current call stack frames."
  (let ((frames)
        (frame)
        (index 5))
    (while (setq frame (backtrace-frame index))
      (push frame frames)
      (incf index))
    (remove-if-not 'car frames)))

在宏中使用它,我们可以查找扩展堆栈,以查看当时正在扩展的函数定义,并将该值正确地放入代码中。

这是执行扩展的功能:

(defmacro compile-time-function-name ()
  "Get the name of calling function at expansion time."
  (symbol-name
   (cadadr
    (third
     (find-if (lambda (frame) (ignore-errors (equal (car (third frame)) 'defalias)))
              (reverse (call-stack)))))))

它在起作用。

(defun my-test-function ()
  (message "This function is named '%s'" (compile-time-function-name)))

(symbol-function 'my-test-function)
;; you can see the function body contains the name, not a lookup
(lambda nil (message "This function is named '%s'" "my-test-function"))

(my-test-function)
;; results in:
"This function is named 'my-test-function'"

原始答案:

您可以使用它backtrace-frame来查找堆栈,直到看到代表直接函数调用的框架并从中获取名称。

(defun get-current-func-name ()
  "Get the symbol of the function this function is called from."
  ;; 5 is the magic number that makes us look 
  ;; above this function
  (let* ((index 5)
         (frame (backtrace-frame index)))
    ;; from what I can tell, top level function call frames
    ;; start with t and the second value is the symbol of the function
    (while (not (equal t (first frame)))
      (setq frame (backtrace-frame (incf index))))
    (second frame)))

(defun my-function ()
  ;; here's the call inside my-function
  (when t (progn (or (and (get-current-func-name))))))

(defun my-other-function ()
  ;; we should expect the return value of this function
  ;; to be the return value of my-function which is the
  ;; symbol my-function
  (my-function))

(my-other-function) ;; => 'my-function

尽管可以在直接扩展为功能符号的宏中实现此功能,但我可能会在运行时执行功能名称查找,这对于重复调用和编译的elisp会更有效。

我在尝试为elisp编写函数调用记录程序时发现了此信息,该信息可以以不完整的形式在此处找到,但对您可能有用。https://github.com/jordonbiondo/call-log


感谢您的代码。这解决了我的问题,除非有人给我们提供某种“ current-function-name”变量,它就是您提示的调试器的一部分,否则我将在几天之内接受它。
2014年

顺便说一句,当a defun被包围时eval-and-compile,即返回似乎无效nil
亚历山大·舒卡耶夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.