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

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

问题描述

如何在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.

谢谢.

相关文章

推荐答案

如另一个答案中所述,这仅在类型不稳定时才有意义.如果这样做,答案是对功能进行分层.有一个顶层进行类型检查和各种设置,然后调用一个使用dispatch的函数来加快速度.例如,

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)(或检查solve中的ODEProblem)导致了不错的加速,它要复杂得多,因为它可以处理到不同封装的转换,但是相同想法).

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.

第二种解决方案将通过强制将您设置为Float64的任何内容强制为Float64来解决任何类型的稳定性(它将尝试转换,如果不能,则转换错误).因此,这可以通过强制类型稳定或错误来提高速度.

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.

关键字spot(@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).

但是请注意,版本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处理kwarg中的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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