0

I have a situation in which the value of the default argument in a function head is affected by an if-clause within the function body. I am using Python 3.7.3.

function definitions

We have two functions f and j. I understand the behavior of the first two function. I don't understand the second function's behavior.

def f(L=[]):
    print('f, inside:   ', L)
    L.append(5)
    return L

def j(L=[]):
    print('j, before if:', L)
    if L == []:
        L = []
    print('j, after if: ', L)
    L.append(5)
    return L

function behavior that I understand

Now we call the first function three times:

>>> print('f, return:   ', f())
f, inside:    []
f, return:    [5]
>>> print('f, return:   ', f())
f, inside:    [5]
f, return:    [5, 5]
>>> print('f, return:   ', f())
f, inside:    [5, 5]
f, return:    [5, 5, 5]

The empty list [] is initialized on the first call of the function. When we append 5 to L then the one instance of the list in the memory is modified. Hence, on the second function call, this modified list is assigned to L. Sounds reasonable.

function behavior that I don't unterstand

Now, we call the third function (j) and get:

>>> print('j, return:   ', j())
j, before if: []
j, after if:  []
j, return:    [5]
>>> print('j, return:   ', j())
j, before if: []
j, after if:  []
j, return:    [5]
>>> print('j, return:   ', j())
j, before if: []
j, after if:  []
j, return:    [5]

According to the output, L is an empty list in the beginning of each call of the function j. When I remove the if-clause, in the body of function j the function is equal to function f and yields the same output. Hence, the if-clause seems to have some side effect. Testing for len(L) == 0 instead of L == [] in j has the same effect.

related to

My question is related to:

But the answers to these question and the tutorial answer only, what I already know.

14
  • 2
    This would be easier to follow if you would you post one function whose behaviour you don't understand, explain your problem with it, and leave out all the other functions. Commented Jul 23, 2019 at 13:21
  • 1
    It's unclear to me why that was unexpected/contrary. Were you expecting L = [] inside the function to change the bound default value? Commented Jul 23, 2019 at 13:21
  • 2
    But why did you expect that? What was your hypothesis for how that would work that led you to expect the same behaviour? Commented Jul 23, 2019 at 13:27
  • 1
    Why should it be? Again, "Were you expecting L = [] inside the function to change the bound default value?" (or L = [5] the same) At the moment you seem to be asking "what's the difference between appending multiple items to a single list and appending a single item each to multiple lists", and the answer seems obvious, so I'm trying to understand where your understanding departs what's happening. Commented Jul 23, 2019 at 13:39
  • 1
    It feels like you could just have answered "yes" either time I asked and saved quite a bit of typing. The same answer was provided a while ago by Jean-François too Commented Jul 23, 2019 at 13:56

3 Answers 3

2

Modify your print statements to also print id(L):

def j(L=[]):
    print('j, before if:', L, id(L))
    if L == []:
        L = []
    print('j, after if: ', L, id(L))
    L.append(5)
    return L

Now check your results:

>>> j()
j, before if: [] 2844163925576
j, after if:  [] 2844163967688
[5]

Note the difference in the IDs. By the time you get to the portion of the function where you modify L, it no longer refers to the same object as the default argument. You've rebound L to a new list (with the L = [] in the body of the if statement), and as a result, you are never changing the default argument.

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

Comments

1

if all boils down to this:

if L == [5]:
    L = []

Here you're not changing the value of the default argument, just binding locally to a new name.

You can do that instead:

if L == [5]:
    L.clear()

or

if L == [5]:
    L[:] = []

to clear the data of the parameter object.

2 Comments

My irritation is related to the function j where we test if L == [].
it's the same thing. The problem is that L name is reassigned (same thing repeated in the accepted answer BTW)
1
def a():
    print "assigning default value"
    return []

def b(x=a()):
    x.append(10)
    print "inside b",x
    return x

print b()
print b()
print b()

try running this. You'll see that default value is not assigned every time you run the function OUTPUT

assigning default value
inside b [10]
[10]
inside b [10, 10]
[10, 10]
inside b [10, 10, 10]
[10, 10, 10]

only once it called the 'a' function to the default value. rest is very well explained above about the compilation of a method so not repeating the same

1 Comment

used python 2.7 so check syntax for print if you are executing on pytohn 3 or above

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.