julia introspection - 获取传递给函数的变量名称

时间:2015-10-03 23:29:03

标签: julia

在朱莉娅,有没有办法得到传递给函数的名字?

x = 10
function myfunc(a)
# do something here
end
assert(myfunc(x) == "x")

我是否需要使用宏或是否存在提供内省的本机方法?

3 个答案:

答案 0 :(得分:7)

您可以使用宏获取变量名称:

julia> macro mymacro(arg)
           string(arg)
       end

julia> @mymacro(x)
"x"

julia> @assert(@mymacro(x) == "x")

但正如其他人所说,我不确定你为什么需要它。

宏在编译期间对AST(代码树)进行操作,x作为符号:x传递给宏。您可以将符号转换为字符串,反之亦然。宏用代码替换代码,因此@mymacro(x)被简单地拉出并替换为string(:x)

答案 1 :(得分:4)

好吧,与我自相矛盾:技术上在一个(相当有限的)条件下,这可能是一种非常黑客的方式:函数名称必须只有一个方法签名。这个想法与Python的问题的答案非常相似。在演示之前,我必须强调这些是内部编译器细节,并且可能会发生变化。简言之:

julia> function foo(x)
           bt = backtrace()
           fobj = eval(current_module(), symbol(Profile.lookup(bt[3]).func))
           Base.arg_decl_parts(fobj.env.defs)[2][1][1]
       end
foo (generic function with 1 method)

julia> foo(1)
"x"

让我再次强调这是一个坏主意,不应该用于任何事情! (好吧,除了回溯显示)。这基本上是“愚蠢的编译器技巧”,但我正在展示它,因为它可以与这些对象一起发挥作用,并且这些解释确实为@ejang的澄清评论提供了更有用的答案。

说明:

  • bt = backtrace()从当前位置生成...回溯... bt是一个指针数组,其中每个指针都是当前调用堆栈中帧的地址。
  • Profile.lookup(bt[3])返回一个带有函数名称的LineInfo对象(以及有关每个帧的其他几个细节)。请注意,bt[1]bt[2]位于回溯生成函数本身,因此我们需要进一步向上移动以获取调用者。
  • Profile.lookup(...).func返回函数名称(符号:foo
  • eval(current_module(), Profile.lookup(...))返回与:foo中名称current_module()相关联的功能对象。如果我们修改function foo的定义以返回fobj,那么请注意REPL中与foo对象的等效性:

    julia> function foo(x)
               bt = backtrace()
               fobj = eval(current_module(), symbol(Profile.lookup(bt[3]).func))
           end
    foo (generic function with 1 method)
    
    julia> foo(1) == foo
    true
    
  • fobj.env.defs返回Method / MethodTable

  • foo中的第一个fobj条目
  • Base.decl_arg_parts是一个辅助函数(在methodshow.jl中定义),它从给定的Method中提取参数信息。
  • 其余的索引向下钻取到参数的名称。

关于函数只有一个方法签名的限制,原因是defs.next中将列出多个签名(请参阅MethodTable)。据我所知,目前没有公开的接口来获取与给定帧地址相关的特定方法。 (作为高级读者的练习:执行此操作的一种方法是修改jl_getFunctionInfo中的地址查找功能,以返回受损的函数名称,然后可以将其与特定的方法调用重新关联;但是,我认为我们目前不存在来自错位名称的反向映射 - >方法)。

还要注意(1)回溯很慢(2)Julia中没有“函数本地”eval的概念,所以即使有一个变量名,我相信实际访问变量是不可能的(并且编译器可能完全忽略局部变量,未使用或以其他方式,将它们放入寄存器等等。)

至于评论中提到的IDE风格的内省使用:foo.env.defs如上所示是“对象内省”的起点。从调试方面,Gallium.jl可以检查给定帧中的DWARF局部变量信息。最后,JuliaParser.jl是Julia解析器的纯Julia实现,它在多个IDE中被主动用于内省高级代码块。

答案 2 :(得分:3)

另一种方法是使用函数vinfo。这是一个例子:

function test(argx::Int64)
    vinfo = code_lowered(test,(Int64,))
    string(vinfo[1].args[1][1])
end
test (generic function with 1 method)

julia> test(10)
"argx"

以上内容取决于知道函数的签名,但如果它在函数本身内编码,则这不是问题(否则可能需要一些宏魔法)。