julia introspection - get name of variable passed to function
在朱莉娅,有没有办法获得传递给函数的名称?
1 2 3 4 5 | x = 10 function myfunc(a) # do something here end assert(myfunc(x) =="x") |
我是否需要使用宏或是否有提供内省的本机方法?
您可以使用宏获取变量名称:
1 2 3 4 5 6 7 8 | julia> macro mymacro(arg) string(arg) end julia> @mymacro(x) "x" julia> @assert(@mymacro(x) =="x") |
但正如其他人所说,我不确定你为什么需要这样做。
宏在编译期间在AST(代码树)上运行,
另一种方法是使用函数的
1 2 3 4 5 6 7 8 | 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" |
以上内容取决于知道函数的签名,但如果它是在函数本身内编码的话,这是一个非问题(否则可能需要一些宏魔法)。
好吧,与我自相矛盾:从技术上讲,这是可能的,在一个(相当有限的)条件下非常黑客的方式:函数名称必须只有一个方法签名。这个想法非常类似于Python的这些问题的答案。在演示之前,我必须强调这些是内部编译器细节,并且可能会发生变化。简述:
1 2 3 4 5 6 7 8 9 | 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(...)) 返回与current_module() 中名称:foo 关联的函数对象。如果我们修改function foo 的定义以返回fobj ,那么请注意REPL中与foo 对象的等价:1
2
3
4
5
6
7
8julia> 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 从MethodTable 返回foo /fobj 的第一个Method 条目 -
Base.decl_arg_parts 是辅助函数(在methodshow.jl 中定义),它从给定的Method 中提取参数信息。 - 索引的其余部分深入到参数的名称。
关于函数只有一个方法签名的限制,原因是
还要注意(1)回溯很慢(2)Julia中没有"函数本地"eval的概念,所以即使有一个变量名,我相信实际上不可能实际访问变量(和编译器)可能完全忽略局部变量,未使用或以其他方式,将它们放入寄存器等)
至于注释中提到的IDE风格的内省使用: