在 Julia 中处理 kwargs 中的类型 [英] dealing with types in kwargs in Julia

查看:11
本文介绍了在 Julia 中处理 kwargs 中的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 Julia 函数中使用 kwargs 并声明它们的类型以提高速度?

How can I use kwargs in a Julia function and declare their types for speed?

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.

Of course I can define the function as f(x::Float64, c::Float64=1.0) to achieve the result, but I have MANY optional arguments with default values to pass, so I'd prefer to use kwargs.

谢谢.

相关帖子

推荐答案

正如另一个答案中所述,这仅在您将遇到类型不稳定时才重要.如果你这样做了,答案就是将你的功能分层.有一个做类型检查和各种设置的顶层,然后调用一个使用调度的函数来快速.例如,

As noted in another answer, this really only matters if you're going to have a type instability. If you do, the answer is to layer your functions. Have a top layer which does type checking and all sorts of setup, and then call a function which uses dispatch to be fast. For example,

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 ... 这可以设置一个复杂的默认值,而不是必须担心类型稳定性,因为它会被内部函数屏蔽.

If most of your time is spent in the inner function, then this will be faster (it might not be for very simple functions). This allows for very general usage too, where you have have a keyword argument be by default nothing and do and if nothing ... which could setup a complicated default, and not have to worry about the type stability since it will be shielded from the inner function.

在DifferentialEquations.jl 中经常使用这种对性能敏感的内部函数的高级类型检查包装器.查看 SDE 求解器的高级包装器 通过确保类型稳定性(内部函数是 sde_solve)(或查看 ODEProblemsolve,从而带来不错的加速效果,它要复杂得多,因为它处理到不同包装的转换,但它是相同的想法).

This kind of high-level type-checking wrapper above a performance sensitive inner function is used a lot in DifferentialEquations.jl. Check out the high-level wrapper for the SDE solvers which led to nice speedups by insuring type stability (the inner function is sde_solve) (or check out the solve for ODEProblem, it's much more complex since it handles conversions to different pacakges but it's the same idea).

此 PR 合并 后,可能会为像您这样的小示例提供更简单的答案.

A simpler answer for small examples like yours may be possible after this PR merges.

为了解决一些混淆,这里有一个声明表:

To fix some confusion, here's a declaration form:

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 或错误,从而导致类型稳定性,但不是一般的解决方案.你使用什么形式真的取决于你在做什么.

This will force anything that saves to c to convert to a Float64 or error, resulting in a type-stability, but is not as general of a solution. What form you use really depends on what you're doing.

最后,还有断言类型,如@TotalVerb 所示:

Lastly, there's also the type assert, as @TotalVerb showed:

function f(x::Float64; c::Float64=1.0, kwargs...)
   return x^2 + c
end

这很干净,或者你可以在函数中断言:

That's clean, or you could assert in the function:

  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 时才断言(转换).

which will cause convertions only on the lines where the assertion occurs (i.e. the @TotalVerb form won't dispatch, so you can't make another function with c::Int, and it will only assert (convert) when the keyword arg is first read in).

  1. 无论用户使用什么类型c,第一个解决方案都会在_f中分派为稳定类型,如果_f 是一个很长的计算,这将获得几乎最佳的性能,但对于非常快速的调用,它会产生调度开销.

  1. The first solution will dispatch to be type stable in _f no matter what type the user makes c, and so if _f is a long calculation, this will get pretty much optimal performance, but for really quick calls it will have dispatch overhead.

第二个解决方案将通过强制将任何您设置的 c 设置为 Float64 来修复任何类型稳定性(它会尝试转换,如果可以的话't,错误).因此,这通过强制类型稳定性或错误来加快速度.

The second solution will fix any type stability by forcing anything you set c to be a Float64 (it will try to convert, and if it can't, error). Thus this gets speed by forcing type stability, or erroring.

关键字位置(@TotalVerb 的答案)中的断言是最干净的,但以后不会自动转换(因此您可能会遇到类型不稳定.但如果您以后不小心转换它,那么你有类型稳定性,可以推断类型,因此你将获得最佳性能)并且你不能将它扩展到函数将 c 作为其他类型传入的情况(无调度).

The assert in the keyword spot (@TotalVerb's answer) is the cleanest, but won't auto-convert later (so you could get a type-instability. But if you don't accidentally convert it later, then you have type stability, types can be inferred, and so you'll get optimal performance) and you can't extend it to cases where the function has c passed in as other types (no dispatch).

最后一个解决方案与 3 几乎相同,只是没有那么好.我不会推荐它.如果您正在使用断言做一些复杂的事情,那么您可能正在设计错误或真的想做第一个类似的事情(在更长的函数调用中调度,它是类型稳定的).

The last solution is pretty much the same as 3, except not as nice. I wouldn't recommend it. If you're doing something complicated with asserts, you likely are designing something wrong or really want to do something like the first (dispatch in a longer function call which is type stable).

但请注意,dispatch with version 3 可能会在不久的将来修复,这将允许您使用 c::Float64c::Int (如有必要)具有不同的功能.希望您的解决方案就在这里.

But note that dispatch with version 3 may be fixed in the near future, which would allow you to have a different function with c::Float64 and c::Int (if necessary). Hopefully your solution is in here somewhere.

这篇关于在 Julia 中处理 kwargs 中的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆