如何在Julia函数中使用kwargs
并声明其类型的速度?
function f(x::Float64; kwargs...)
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c::Float64 = kwargs[:c]
else
c::Float64 = 1.0
end
return x^2 + c
end
f(0.0, c=10.0)
的产率:
ERROR: LoadError: syntax: multiple type declarations for "c"
当然我可以将函数定义为f(x::Float64, c::Float64=1.0)
来实现结果,但是我有许多可选参数,默认值要传递,所以我更喜欢使用kwargs。
感谢。
答案 0 :(得分:5)
正如另一个答案所指出的那样,这真的很重要,如果你的类型不稳定。如果你这样做,答案就是分层你的功能。有一个顶层进行类型检查和各种设置,然后调用一个使用dispatch快速的函数。例如,
function f(x::Float64; kwargs...)
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c = kwargs[:c]
else
c = 1.0
end
return _f(x,c)
end
_f(x,c) = x^2 + c
如果大部分时间花在内部函数上,那么这将更快(可能不是非常简单的函数)。这也允许非常一般的使用,你有一个关键字参数默认为nothing
和do if nothing ...
可以设置一个复杂的默认值,而不必担心类型的稳定性,因为它会被屏蔽内功能。
这种高性能类型检查包装器在性能敏感的内部函数之上,在DifferentialEquations.jl中经常使用。查看高级包装器for the SDE solvers,通过确保类型稳定性(内部函数为sde_solve
)(或查看solve
ODEProblem
)来获得良好的加速,这是更复杂,因为它处理转换到不同的pacakges,但它是相同的想法)。
在this PR merges之后,可能会对像你这样的小例子做出更简单的回答。
为了解决一些困惑,这里有一个声明表格:
function f(x::Float64; kwargs...)
local c::Float64 # Ensures the type of `c` will be `Float64`
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c = float(kwargs[:c])
else
c = 1.0
end
return x^2 + c
end
这将强制保存到c
的任何内容转换为Float64
或错误,从而导致类型稳定,但不是解决方案的一般性。你使用什么形式取决于你正在做什么。
最后,还有类型断言,正如@TotalVerb所示:
function f(x::Float64; c::Float64=1.0, kwargs...)
return x^2 + c
end
那很干净,或者你可以在函数中断言:
function f(x::Float64; kwargs...)
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c = float(kwargs[:c])::Float64
else
c = 1.0
end
return x^2 + c
end
这将导致仅在发生断言的行上进行转换(即@TotalVerb表单不会发送,因此您不能使用c::Int
创建另一个函数,并且它只会断言(转换)时首先读入关键字arg)。
无论用户使用什么类型_f
,第一个解决方案都会在c
中调度为类型稳定,因此如果_f
是一个长计算,这将得到非常优化的性能,但对于非常快速的调用,它将有调度开销。
第二个解决方案会通过强制将c
设置为Float64
的任何内容来强制修复任何类型的稳定性(它会尝试转换,如果不能,则会发生错误)。因此,这会通过强制类型稳定性或错误来获得速度。
关键字spot中的断言(@ TotalVerb的答案)是最干净的,但稍后不会自动转换(因此您可能会遇到类型不稳定。但如果您以后不小心转换它,那么你有类型稳定性,类型可以被推断,因此你将获得最佳性能)并且你不能将它扩展到函数具有c
作为其他类型(无调度)传入的情况。
最后的解决方案与3完全相同,但不是很好。我不推荐它。如果你正在做一些复杂的断言,你可能正在设计一些错误的东西,或者真的想做一些像第一个那样的东西(在较长的函数调用中调度,类型稳定)。
但请注意dispatch with version 3 may be fixed in the near future,这将允许您使用c::Float64
和c::Int
(如果需要)具有不同的功能。希望你的解决方案就在这里。
答案 1 :(得分:2)
请注意,声明类型不会提高性能;您可能希望放宽x
和c
上的类型约束,以使您的代码更通用。无论如何,这可能是你想要的:
function f(x::Float64; c::Float64=1.0, kwargs...)
return x^2 + c
end
请参阅手册的keyword arguments部分。