Why mutable default parameter behaves this way?

Question:

I’m aware of mutable parameter behavior. Why the list is not set up to None when I send and unpack **dictionary as argument? The common_header.png repeads, it means is stored in list. That is weird to me and I couldn’t find answer for the question…
I’m learning, happy to hear any other suggestions to code, thank you

def print_user_profile(gender='female', first='Jane', last='Doe=', pictures = None):
    if pictures is None: pictures = []
    gender_options = ('male', 'female')
    
    if gender not in gender_options: return 'Gender not correct'
    elif gender == 'male' and first == 'Jane': first = 'John'

    pictures.insert(0, 'common_header.png')

    print(f'The user {first} {last} has the following pictures:')
    for i in pictures: print(i)  
test_data1 = {
    "gender": "male",
    "last": "Brown",
    "pictures": ["holidays1.png", "easter_grandma.png"]
}

print_user_profile(gender='male', last='Brown', pictures=["holidays1.png", "easter_grandma.png"]) 
print_user_profile(gender='male', last='Brown', pictures=["holidays1.png", "easter_grandma.png"]) 
print_user_profile(gender='male', last='Brown', pictures=["holidays1.png", "easter_grandma.png"]) 

print_user_profile(**test_data1) 
print_user_profile(**test_data1) 
print_user_profile(**test_data1)

The user John Brown has the following pictures:  
common_header.png
holidays1.png
easter_grandma.png

The user John Brown has the following pictures:
common_header.png
holidays1.png
easter_grandma.png

The user John Brown has the following pictures:
common_header.png
holidays1.png
easter_grandma.png

The user John Brown has the following pictures:
common_header.png
holidays1.png
easter_grandma.png

The user John Brown has the following pictures:
common_header.png
common_header.png
holidays1.png
easter_grandma.png

The user John Brown has the following pictures:
common_header.png
common_header.png
common_header.png
holidays1.png
easter_grandma.png

There is no problem if I send the same arguments separately.

Asked By: Paul-Mazu

||

Answers:

In your code, when you pass the list explicitly to each call, you create a new instance of the list.

When you pass as a dictionary, you are calling with a single instance of that list three times.

We could change your code to use the same list six times, and you’ll see the same behavior with both calling conventions.

pictures = ["holidays1.png", "easter_grandma.png"]

test_data1 = {
    "gender": "male",
    "last": "Brown",
    "pictures": pictures
}

print_user_profile(gender='male', last='Brown', pictures=pictures) 
print_user_profile(gender='male', last='Brown', pictures=pictures) 
print_user_profile(gender='male', last='Brown', pictures=pictures) 
print_user_profile(**test_data1) 
print_user_profile(**test_data1) 
print_user_profile(**test_data1)

Which outputs:

The user John Brown has the following pictures:
common_header.png
holidays1.png
easter_grandma.png
The user John Brown has the following pictures:
common_header.png
common_header.png
holidays1.png
easter_grandma.png
The user John Brown has the following pictures:
common_header.png
common_header.png
common_header.png
holidays1.png
easter_grandma.png
The user John Brown has the following pictures:
common_header.png
common_header.png
common_header.png
common_header.png
holidays1.png
easter_grandma.png
The user John Brown has the following pictures:
common_header.png
common_header.png
common_header.png
common_header.png
common_header.png
holidays1.png
easter_grandma.png
The user John Brown has the following pictures:
common_header.png
common_header.png
common_header.png
common_header.png
common_header.png
common_header.png
holidays1.png
easter_grandma.png
Answered By: Bill Lynch

Your bug is of course straight forward, but I can see it can be challenging in the start. you repeatedly give the "pictures" element of "test_data_1", and that one is then mutated within your function.

If you want to avoid that, make a copy of the list inside the function, e.g. via

pictures = [] if pictures is None else list(pictures)
Answered By: Dr. V