Populating a dictionary using a function with arbitrary keyword arguments

I’m really confused about how to go about populating a dictionary with a function involving arbitrary keyword arguments.

I’ve been practicing Julia by working through a book about Python and re-writing the code snippets using Julia.

This is the Python code snippet that I’m having difficulty with:

def build_profile(first, last, **user_info):
       """Build a dictionary containing everything we know about a user."""
       user_info['first_name'] = first
       user_info['last_name'] = last
       return user_info

   user_profile = build_profile('albert', 'einstein', location='princeton', field='physics')

I came up with something like this, but only the first and last name make their way into the dictionary:

function build_profile(first, last; user_info...)
    user_info = Dict(:first_name => first, :last_name => last)
    return user_info
end

user_profile = build_profile("albert", "einstein", location="princeton", field="physics")
println(user_profile)

What would the equivalent in Julia look like?

You’re not using user_info inside your function, so I’m not sure why one would expect those keywords to do anything (I see that Python is doing this but I’d argue this is pretty surprising behaviour).

Be that as it may, kwargs in Julia show up in the function as key/val pairs so you can just splat them into your dictionary:

julia> function build_profile(first, last; user_info...)
           Dict(:first_name => first, :last_name => last, user_info...)
       end
build_profile (generic function with 1 method)

julia> build_profile("albert", "einstein", location="princeton", field="physics")
Dict{Symbol, String} with 4 entries:
  :location   => "princeton"
  :field      => "physics"
  :last_name  => "einstein"
  :first_name => "albert"
4 Likes

Thank you for your help! I didn’t think of putting user_info... inside of the function. Python doesn’t require it, yet it still works, which is why I was confused as to what was needed for it to work in Julia.

Yes, that’s why I checked python to verify that this works. I find it pretty confusing that an unused argument all of a sudden appears in the result in this way, but maybe there’s some deeper python mechanism this is consistent with -someone with better python knowledge than me would have to chime in.

In Python keyword arguments are internally a dictionary, analogous to e.g. class attributes (__dict__).

This is not the case in julia for performance reasons and to avoid allocations.

Also note that the Julia code wouldn’t work in Python either as written.

Sorry I know this is not a Python forum but I’m interested so maybe you’ll indulge me: are you saying that the reason this works in Python is that when I do def f(x, **my_kwargs) the function will always have a dictionary object names my_kwargs in its scope which I can return? So doing my_kwargs['new_entry'] = "something" will write to this existing object?

Actually I hadn’t noticed that there’s never any dictionary explicitly created in the Python function at all, so I guess this must be the case. It’s then just that in Julia the kwargs aren’t a Dict:

julia> f(; kwargs...) = kwargs
f (generic function with 1 method)

julia> f(a = 1, b = "c")
pairs(::NamedTuple) with 2 entries:
  :a => 1
  :b => "c"

Yes:

>>> def f(**kwargs):
...     kwargs['foo'] = 42
...     return kwargs
...
>>> f(bar=9)
{'bar': 9, 'foo': 42}
1 Like