Why do Julia functions handle keyword arguments as `Base.Pairs` instead of `NamedTuple` or `Dict`?

In Python, where we use *args and **kwargs to handle an arbitrary number of positional and keyword arguments in a function. In Python, these positional arguments are gathered into a tuple, and keyword arguments are gathered into a dictionary:

def my_function(*args, **kwargs):
    return args, kwargs

result = my_function(1, 2, 3, a=4, b=5, c=6)
print(result)  # Outputs: ((1, 2, 3), {'a': 4, 'b': 5, 'c': 6})

However, in Julia it is different

function my_function(args...; kwargs...)
    return args, kwargs

my_function(1, 2, 3, a=4, b=5, c=6)
# Outputs: ((1, 2, 3), Base.Pairs(:a => 4, :b => 5, :c => 6))

Here, I see that the keyword arguments are returned as a Base.Pairs object, not a NamedTuple or a Dict as I expected.

Why does Julia use Base.Pairs to capture keyword arguments instead of NamedTuple or Dict? What are the benefits or use cases of Base.Pairs in this context?




As far as I understand Change keyword arguments back to regular NamedTuples by ararslan · Pull Request #25711 · JuliaLang/julia · GitHub, the use of Pairs in 2018 is that when you iterate those keyword arguments, iterating both key and value is more often desired, where Pair is the right choice. And iterating NamedTuples only gives you the value of each item.

Kind of reasonable now.