-2

I was reading this very informative question and answer and learned about this behavior for the first time: calling

def foo(l=[]):
    l.append(1)
    print(l)

foo()
foo()
foo([])
foo()

prints

[1]
[1,1]
[1]
[1,1,1]

I thought that was neat and wanted to try it with other variable types as default arguments.

Running

import math
def foo(l=[],bar=0,baz={"z":0},bap="a"):
    l.append(1)
    bar+=1
    baz["z"]+=1
    bap=chr(ord(bap)+1)
    print(locals())

foo()
foo()
foo([],math.pi,{"z":0},"?")
foo()

prints

{'l': [1], 'bar': 1, 'baz': {'z': 1}, 'bap': 'b'}
{'l': [1, 1], 'bar': 1, 'baz': {'z': 2}, 'bap': 'b'}
{'l': [1], 'bar': 4.141592653589793, 'baz': {'z': 1}, 'bap': '@'}
{'l': [1, 1, 1], 'bar': 1, 'baz': {'z': 3}, 'bap': 'b'}

which caught me totally off-guard. I was expecting incrementing the integer bar and string bap to be analogous to appending/modifying elements of l and baz and cause similar behavior, but it didn't - they print the same values each foo call (unless non-default arguments are provided).

Hence the question in the title. I was thinking that the difference was caused by iterable versus non-iterable data types in my example.

1

1 Answer 1

0

I learned from another informative post and a helpful link therein that my suspicion was off-target. The issue isn't caused by iterable versus non-iterable types.

The difference in default argument behavior happens because some of those default arguments I chose are mutable (l list, baz dict) and others are immutable (bar int, bap str).

Sign up to request clarification or add additional context in comments.

5 Comments

So, you post question in order to answer it yourself? Both asked and answered 10 minutes ago... This will be closed as dupe in no time.
@buran, I'm not trying to "dupe" anyone. I sincerely believed iterable and non-iterable data types were the cause of this behavior, couldn't find a satisfactory answer about iterable arguments in docs or SO, spent an hour researching Python iterability and writing my question, then stumbled on this post by chance. I hope that someone else who tries to understand this behavior by researching iterability and has no clue about mutable arguments will avoid the same dead-end that I was going down.
Thank you for clarifying that you meant "dupe" as in "duplicate," not "dupe" as in "cruel trick." It seems that the thrust of the question would be more clear with "iterable" in the title, so I'll make that modification. The SO blog alleged "it is not merely OK to ask and answer your own question, it is explicitly encouraged", and encountering a question with this explanation of the behavior would have saved me over an hour.
By the way, one more reference docs.python.org/3/faq/… By definition, immutable objects such as numbers, strings, tuples, and None, are safe from change. Changes to mutable objects such as dictionaries, lists, and class instances can lead to confusion.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.