Abby
Abby

Reputation: 1

How comes the syntax changes for dicts (since apparently keys must be strings) when using **kwargs?

In this piece of code for example, keys seem to be keywords using the '=' sign instead of the usual dict syntax {"key":"value"} as in the second piece of code

    def myfunc(**kwargs):
        if "fruits" in kwargs:
            print(f"My fruit of choice is {kwargs['fruits']}")
        else:
            print("I did not find any fruit here")
    myfunc(fruits = "apple", veggies = "cabbage")



    my_dict = {"fruits":"apple", "veggies":"cabbages"}
    my_dict["fruits"]

Upvotes: 0

Views: 29

Answers (1)

chepner
chepner

Reputation: 532003

Keyword arguments predate the ability to specify arbitrary keyword arguments. In the beginning, there were only positional parameters:

def foo(a, b):
    ...

and you could only specify positional arguments:

foo(3, 5)

Next came keyword arguments: you could specify the parameters by name at call time, both for readability and to relax the requirement to provide arguments in the order they were defined:

foo(a=3, b=5)
foo(b=5, a=3)  # Identical to the above

Later, the ability to add keyword arguments that weren't predefined as parameters was added. These are exposed inside the function as a dict, created at call time, and assigned to the parameter prefixed with **:

def foo(a, b, **kwargs):
    ...

foo(a=3, b=5, c=9)  # kwargs['c'] will have the value 9.

No change was made to the calling syntax; as far as the caller is concerned, the fact that a dict is used to access the value of c is an implementation detail, and one that is not exposed outside the function.

A separate, but related, use of ** is to unpack a dict as a sequence of keyword arguments:

foo(**{'a': 3, 'b': 5})  # Equivalent to foo(a=3, b=5)

Upvotes: 1

Related Questions