1

In this article https://florimond.dev/blog/articles/2018/08/python-mutable-defaults-are-the-source-of-all-evil/ the following code is posted as the pythonic solution:

def append(element, seq=None):
    if seq is None:
        seq = []
    seq.append(element)
    return seq 

To the problem of having default arguments with lists. To me it does not seem pretty and I wondered if there is someway to be able to have a mutable defaults and no if statement. Something like:

def append(element, seq=defaultlist([])):
    seq.append(element)
    return seq  
Peter Mølgaard Pallesen
  • 1,470
  • 1
  • 15
  • 26
  • tried `def append(element, seq=[])` ?? – Sowjanya R Bhat Jun 25 '20 at 14:45
  • 1
    Version 1 is the solution every Python programmer instantly understands when reading the code. – timgeb Jun 25 '20 at 14:45
  • The whole problem with mutable defaults is that they're only evaluated *once*, when the function was originally defined. No conceivable definition of your `defaultlist` would result in each invocation of the function having its own separate list. – jasonharper Jun 25 '20 at 14:46
  • @jasonharper I'd substitute conceivable with sane. – timgeb Jun 25 '20 at 14:47
  • I know that the version 1 is the standard, but honestly having a default list would communicate the actural meaning of the default argument and meaning much better. You would not have to look into the code for what the default argument was, which I do now. Especially when combining this with automatic documentation. We all just want to write ´def append(element, seq=[])´ – Peter Mølgaard Pallesen Jun 25 '20 at 14:55

1 Answers1

0

The comments you got so far are correct. For further explanation about this, see "Least Astonishment" and the Mutable Default Argument

However, there's actually a work-around for what you want. I wouldn't say it's more elegant than the version 1 (that everyone uses), and it also requires one line of code inside your function: You have to create a copy of seq inside the function, so it's this copy which gets updated, and not the 'default' seq:

def foo(x, seq=[]): 
    seq = list(seq)
    seq.append(x)
    return seq

Then test it:

>>> foo(1)
[1]
>>> foo(2)
[2]
>>> foo(3, ['a', None])
['a', None, 3]
>>> foo(4)
[4]