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?
Passing Dictionary as an argument In Python, everything is an object, so the dictionary can be passed as an argument to a function like other variables are passed. “ kwargs ” stands for keyword arguments.
In Julia, values are passed and assigned by reference.
A return type can be specified in the function declaration using the :: operator. This converts the return value to the specified type. This function will always return an Int8 regardless of the types of x and y .
Function is an abstract type. So for example Vector{Function} is like a Vector{Any} , or Vector{Integer} : Julia just can't infer the results.
As a heuristic, Julia avoids automatically specializing on argument type parameters in three specific cases: Type, Function, and Vararg. Julia will always specialize when the argument is used within the method, but not if the argument is just passed through to another function.
Julia provides a pre-defined function to access elements of a Dictionary known as get () function. This function takes 3 arguments: dictionary name, key, and a default value to print if the key is not found. Dictionaries in Julia allow accessing all the keys and all the values at once.
Julia function arguments follow a convention sometimes called "pass-by-sharing", which means that values are not copied when they are passed to functions. Function arguments themselves act as new variable bindings (new locations that can refer to values), but the values they refer to are identical to the passed values.
In simple words, whenever the function will be called with arguments of a new type, the Julia compiler will generate a separate version of that function. On the other hand, a function for a specific combination of arguments types is called a Method.
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.
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...)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With