11

I am noticing the following:

class c:
  def __init__(self, data=[]):
    self._data=data
a=c()
b=c()
a._data.append(1)
print b._data
[1]

Is this the correct behavior?

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
rs1
  • 167
  • 1
  • 6
  • 2
    Please read the markup documentation to see how to correctly format code. It's on the right side of the page. Please update your question to indent the code 4 spaces. – S.Lott Feb 22 '10 at 18:22
  • Related: http://stackoverflow.com/questions/1011431/python-things-one-must-avoid, http://stackoverflow.com/questions/1534407/python-object-intialization-bug-or-am-i-misunderstanding-how-objects-work, http://stackoverflow.com/questions/1651154/why-are-default-arguments-evaluated-at-definition-time-in-python – S.Lott Feb 22 '10 at 19:10

3 Answers3

13

Yes, it's correct behavior.

However, from your question, it appears that it's not what you expected.

If you want it to match your expectations, be aware of the following:

Rule 1. Do not use mutable objects as default values.

def anyFunction( arg=[] ):

Will not create a fresh list object. The default list object for arg will be shared all over the place.

Similarly

def anyFunction( arg={} ):

will not create a fresh dict object. This default dict will be shared.

class MyClass( object ):
    def __init__( self, arg= None ):
        self.myList= [] if arg is None else arg 

That's a common way to provide a default argument value that is a fresh, empty list object.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 3
    `Will never work.` is a bit harsh. `Won't give you a new empty mutable object on each call`, seems a little more balanced. If you know this happens you might actually want to use this behaviour. – MattH Feb 22 '10 at 18:37
  • 1
    @MattH: Reusing the same mutable object via a default value is so odd that it defies finding a sensible use case. It's a *default* value, so it may (or may not) get used as such depending on the client's use of the interface. It would be so hard to diagnose problems with this that I stand by my original formulation. Especially for n00bz. – S.Lott Feb 22 '10 at 18:40
  • You should add an example of how to work around this. Otherwise the answer is good and correct. – ironfroggy Feb 22 '10 at 18:48
  • There's a sensible use case for almost everything. For mutable default values I'd choose a simple memoization strategy, for example as described by Alex Martelli here: http://stackoverflow.com/questions/1651154/why-are-default-arguments-evaluated-at-definition-time-in-python/1651284#1651284 – Scott Griffiths Feb 22 '10 at 23:16
  • 1
    @Scott Griffiths: While there's a use case, I would debate "sensible". Yes, it works, but so does unreadable spaghetti code. Using mutable objects as *default* values is a bad idea. In the example question, the default value syntax is used to provide a hidden memoization context; it doesn't fit the usual design patterns for "default" because there is o sensible reason to provide a real value. – S.Lott Feb 23 '10 at 02:04
4

This is a classic pitfall. See http://zephyrfalcon.org/labs/python_pitfalls.html, section 5: "Mutable default arguments"

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
1

Always make functions like this then:

def __init__ ( self, data = None ):
    if data is None:
       data = []

    self._data = data

Alternatively you could also use data = data or [], but that prevents the user from passing empty parameters ('', 0, False etc.).

poke
  • 369,085
  • 72
  • 557
  • 602
  • Of course you can also do `if not data: data = []`. – Esteban Küber Feb 22 '10 at 18:56
  • your example `data = data or []` works just fine for empty lists being passed. You'd be saying `data` will be `[] or []` so it will look at the first one and see that it evaluates to "false", then it will take the other value. – tgray Feb 22 '10 at 20:14
  • 1
    I know, my point was that when you pass `False` for example, `[]` will be used as the value, although you passed `False`. – poke Feb 22 '10 at 20:23