在朱莉娅,有没有办法得到传递给函数的名字?
x = 10
function myfunc(a)
# do something here
end
assert(myfunc(x) == "x")
我是否需要使用宏或是否存在提供内省的本机方法?
答案 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"
以上内容取决于知道函数的签名,但如果它在函数本身内编码,则这不是问题(否则可能需要一些宏魔法)。