3

I have this piece of code:

kwargs_input = {"name": "lala", "age": 25, "postcode": 17867}

def print_kwargs(**kwargs):
    for k,v in kwargs.items():
        print(k,v)

def func_print(name="lolo", age=56, **kwargs):
    print_kwargs(**kwargs)

print(func_print(**kwargs_input))

It prints:

postcode 17867
None

I have two questions:

  1. Why name and age are not printed? I was expecting to override the default value of name (lolo) and age (56) with the arguments passed as **kwargs_input. Is that possible?
  2. Where does None come from?

3 Answers 3

9
  1. Neither name nor age are printed, because they have been removed from kwargs during the function call. Inside the function call you have access to both name and age through those variables. kwargs will contain the rest of the 'variables'.
  2. The None is returned from func_print() by default and your print(func_print()) prints it out.
Sign up to request clarification or add additional context in comments.

2 Comments

What can I do to make kwargs have default value? For example, if I don't set name in kwargs_input, I want kwargs to take the default value which is lolo.
You can add: kwargs['name'] = name inside the function (etc for each parameter with a default) to update kwargs with all the parameters.
2

name and age aren't packed into the first kwargs in func_print() therefore aren't passed further into other functions. Or in other words, it's not collecting all arguments, it's only collecting arguments that are unspecified, "dangling", so that it doesn't throw an error. Similar to Varargs in C.

None comes from the func_print()'s return as it's the default value of any function.

For example:

def func():
    ...  # check help(...) and type(...)
    # implicit "return None"

def func():
    pass
    # implicit "return None"

def func():
    return
    # implicit "return None"

def func():
    # explicit return None
    return None

What you can however do is something that's common in JavaScript nowadays, send an object as an argument. Fortunately, you don't need to create and pass a custom object instance or anything like that because just **kwargs itself is a syntax that creates a dictionary (alternatively *args creates a tuple), so an object's instance preserving the arguments. (Similarly, you can use *args for positional arguments, more on that here).

From that you can do this:

def other(**kwargs):
    print(kwargs)

def func(**kwargs):
    print(kwargs.get("name", "lolo"))
    other(**kwargs)

print(func(name=123, hello="world"))
# 123
# {'name': 123, 'hello': 'world'}
# None
print(func(hello="world"))
# lolo
# {'hello': 'world'}
# None

Comments

0

Key here is that **dict in python unrolls the dict to key value pairs in the function call.

kwargs_input = {"name": "lala", "age": 25, "postcode": 17867}

def print_kwargs(**kwargs):
    for k,v in kwargs.items():
        print(k,v)

def func_print(name="lolo", age=56, **kwargs):
    print_kwargs(**kwargs)

# Equivalent to passing **kwargs_input
print(func_print(name='lala', age=25, postcode=17867))

**kwargs then captures all those 'extra' key word arguments not specified in the function definiton.

As you can see name and age are.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.