Reputation: 1054
I have a dictionary of function arguments that I want to pass to a function. For example:
function test_function(foo::Int, bar::String)
#...
end
params = Dict(
"foo" => 1,
"bar" => "baz"
)
In Python, I could pass all parameters as kwargs like this:
def test_function(foo: int, bar: str):
#...
params = {
"foo": 1
"bar": "baz"
}
test_function(**params)
But when I try params...
, I get the following error:
julia> test_function(params...)
ERROR: MethodError: no method matching test_function(::Pair{String,Any}, ::Pair{String,Any})
Is there a way to do anything similar in Julia?
Upvotes: 6
Views: 2927
Reputation: 18530
EDIT: Oops posted this just after Cameron's answer. I'll leave it here in case it is helpful, but honestly, it says pretty much the same thing as his answer :-)
In Julia, the generic function signature is f(args ; kwargs)
. The names of the regular input arguments args
don't really matter, it is the order in which they appear in the function signature that is important. In contrast, for the keyword arguments kwargs
it the name that matters, and the order is not important.
The final piece of information we need is that for either args
or kwargs
, the splatting operator ...
separates out the elements of the container being splatted into individual arguments for the function signature.
So, let's apply this all to your example. Consider the following two functions:
function f1(foo::Int, bar::String)::String
return "$(foo) --> $(bar)"
end
function f2( ; foo::Int=0, bar::String="nil")::String
return "$(foo) --> $(bar)"
end
The first function only has args
while the second function only has kwargs
. In the case of the first function, names don't matter since we're dealing with args
, so in order to splat a container we would use just use a vector or tuple, e.g.:
params = [1, "baz"]
f1(params...)
The second function only has kwargs
, and Julia expects to see these expressed as the type Pair{Symbol,T}
for some T<:Any
. So, if we construct our dictionary to map the name of the keyword argument (expressed as a Symbol
) to the value, then the splatting operator will splat each entry of the dictionary into the function signature like so:
params = Dict(:foo=>1, :bar=>"baz")
f2(; params...)
Note that I had to use ;
in the function call to indicate there were no args
, only kwargs
.
And of course, if needed, you can have both at the same time, e.g. f3(vectorofargs... ; dictofargs...)
.
Upvotes: 4
Reputation: 7664
Julia makes a clear distinction between positional arguments and keyword arguments. To clarify the distinction, you can separate positional arguments from keyword arguments with a semicolon. You can unpack objects into positional arguments or keyword arguments using ...
, which is referred to as the splatting operator.
If you want to unpack an object into keyword arguments, it needs to be an iterator of pairs or tuples. If you unpack an object into positional arguments, the unpacked element types need to match one of the methods of the function.
Here's an example:
function foo(x, y; a=1, b=2)
x + y + a + b
end
t = (1, 2)
d = Dict(:a => 3, :b => 4)
julia> foo(t... ; d...)
10
However, note that the keys in the dictionary (or iterator of pairs/tuples) must be symbols in order for unpacking into keyword arguments to work:
julia> e = Dict("a" => 3, "b" => 4);
julia> foo(t... ; e...)
ERROR: MethodError: Cannot `convert` an object of type String
to an object of type Symbol
For more info, see the Varargs and Keyword Arguments sections of the manual.
Upvotes: 13