如何在第一次调用Julia函数时执行某些代码



我有一个特定的用例,我希望函数在第一次被调用时基本上提供警告,告诉用户一些信息。除了使用全局计数器并跟踪函数被调用的次数之外,我不确定如何检查这一点。关于特定的Julia语法,有什么想法可以让我检查该函数是否是第一次被调用的吗?

当您可以选择重写函数体时,以下是如何做到这一点的一些想法所有这些也可以通过编写一个相当简单的宏来执行相应的转换来实现好吧,如果你想让顶级和本地定义正常工作,这并不是那么简单。

(非(选项1

从概念上讲,你可以用一个生成的函数来实现这一点,当你尝试它时,它将主要起作用:

julia> @generated function dostuff(x)
@warn "You really shouldn't do stuff!"
return :(2x + 1)
end
dostuff (generic function with 1 method)
julia> dostuff(1)
┌ Warning: You really shouldn't do stuff!
└ @ Main REPL[1]:2
3
julia> dostuff(1)
3

但是:不要。编译器可以自由选择何时调用";发电机";,引用文档的话:这些副作用将在何时、多久或多少次发生还没有定义。不是个好主意。

此外,@warn是否会使用生成的函数中允许的打印函数也是值得怀疑的。在早期的Julias中,使用println而不是Core.println有时会在生成的函数中出错,因为前者修改了事件循环。

选项2

所以为了更好的东西。与全局计数器的想法不同,您可以通过将函数定义为let bound变量的闭包来执行类似的操作:

julia> let isfirstcall = Threads.Atomic{Bool}(true)
global function dostuff(x) 
if Threads.atomic_xchg!(isfirstcall, false)
@warn "You really shouldn't do stuff!"
end
return 2x + 1
end
end
dostuff (generic function with 1 method)
julia> dostuff(1)
┌ Warning: You really shouldn't do stuff!
└ @ Main REPL[16]:4
3
julia> dostuff(1)
3
julia> isfirstcall
ERROR: UndefVarError: isfirstcall not defined

我在这里选择使用原子只是为了atomic_xchg!的乐趣,但如果线程不是问题,那么简单的布尔值也可以。

选项3

此外,虽然可以避免,但如果你做对了,全局变量也不会太糟糕。意思是:使其成为constRef。并且(可选,但在本例中建议使用(,使用var字符串为其指定一个用户通常无法访问的名称:

julia> const var"##isfirstcall" = Ref(true)
julia> function dostuff(x)
if var"##isfirstcall"[]
@warn "You really shouldn't do stuff!"
var"##isfirstcall"[] = false
end
return 2x + 1
end
dostuff (generic function with 1 method)
julia> dostuff(1)
┌ Warning: You really shouldn't do stuff!
└ @ Main REPL[22]:3
3
julia> dostuff(1)
3

使用日志宏的maxlog功能:

julia> function warnfirst(x, y)
@warn "This is the first time you called this" maxlog=1
return 2x + y
end
warnfirst (generic function with 1 method)
julia> warnfirst(1, 2)
┌ Warning: This is the first time you called this
└ @ Main REPL[1]:2
4
julia> warnfirst(1, 2)
4
julia> warnfirst(1.0, 2.0)   # what about different specializations?
4.0

最新更新