Jan Willem Feitsma
Jan Willem Feitsma

Reputation: 13

How to access kwargs created in an other function using python?

I'm working on large Finite Element Analysis code with a lot a functions. To pass variables between different functions I make use of python's kwargs. I mainly opted for this so that I can call the functions in a lot of different ways, creating a great flexibility.

However now I'm dealing with a problem. From a main function I call another function using the kwargs. This second function then processes the input and adds new kwargs. The problem is that the new kwargs created in that function are not accessible in the first one. Is there a pythonic way of doing this? I created the following code as an example:

# Create main function
def main(**kwargs):
    # Add a key word argument
    kwargs["textMain"] = "text added in main"

    # Call a function with existing kwargs and a new one
    functionA(textNew = "text added in new" ,**kwargs)

    # Test what is in kwargs after subfunction is called
    print("\nTest kwargs after subfunction is called:")

    if "textMain" in kwargs:
        print(kwargs["textMain"])

    if "textNew" in kwargs:
        print(kwargs["textNew"])

    if "textA" in kwargs:
        print(kwargs["textA"])

def functionA(**kwargs):

    # Test kwargs before adding kwargs in subfunction
    print("\nTest kwargs in subfunction before adding:")

    if "textMain" in kwargs:
        print(kwargs["textMain"])

    if "textNew" in kwargs:
        print(kwargs["textNew"])

    if "textA" in kwargs:
        print(kwargs["textA"])

    # Add kwargs
    kwargs["textA"] = "text added in sub A"

    # and test kwargs again
    print("\nTest kwargs in subfunction after adding:")
    if "textMain" in kwargs:
        print(kwargs["textMain"])

    if "textNew" in kwargs:
        print(kwargs["textNew"])

    if "textA" in kwargs:
        print(kwargs["textA"])

if __name__ == "__main__":
    main()

This yields the following output:

#Test kwargs in subfunction before adding:
#text added in main
#text added in new

#Test kwargs in subfunction after adding:
#text added in main
#text added in new
#text added in sub A

#Test kwargs after subfunction is called:
#text added in main

where my prefered output would be:

#Test kwargs in subfunction before adding:
#text added in main
#text added in new

#Test kwargs in subfunction after adding:
#text added in main
#text added in new
#text added in sub A

#Test kwargs after subfunction is called:
#text added in main
#text added in new
#text added in sub A

It would be of great help if any one could solve my problem. Thanks in advance!

Upvotes: 1

Views: 669

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121366

When you use the **kwargs syntax in a call expression, Python expands the dictionary and passes in separate arguments. The same syntax in the function signature then tells Python to create a new dictionary in that function to capture the keyword arguments.

In other words, kwargs in main() is not the same dictionary as the one in functionA().

Either pass in the actual dictionary (not using **kwargs syntax) or have functionA() return a new dictionary.

Passing in kwargs as a single argument lets you alter the dictionary from functionA() and see the changes reflected in main(), as they now share a reference to the same dictionary:

def main(**kwargs):
    functionA(kwargs, textNew="text added in new")
    # ... etc ...


def functionA(mapping, **kwargs):
    # do something with mapping, it is the same dictionary as kwargs in main

Returning the updated kwargs dictionary from functionA() requires that you assign the new object back to kwargs in main():

def main(**kwargs):
    kwargs = functionA(textNew="text added in new", **kwargs)
    # ... etc ...

def functionA(**kwargs):
    # ...
    return kwargs

Upvotes: 2

Related Questions