Strange Behavior

Discussion in 'Python' started by abcd, Oct 16, 2006.

  1. abcd

    abcd Guest

    class Foo:
    def __init__(self, name, data=[]):
    self.name = name
    self.data = data

    def addData(self, val):
    self.data.append(val)


    f = Foo('a')
    f.addData(1)
    f.addData(2)

    f2 = Foo('b')

    print f.name, f.data
    print f2.name, f2.data

    ----------------------------
    OUTPUT
    ---------------------------
    a [1, 2]
    b [1, 2]


    .....why would f and f2 contain the same data??

    however, if I do this instead....

    f = Foo('a')
    f.addData(1)
    f.addData(2)

    f2 = Foo('b', [])

    print f.name, f.data
    print f2.name, f2.data

    ----------------------------
    OUTPUT
    ---------------------------
    a [1, 2]
    b []


    Any ideas? is this a bug?
     
    abcd, Oct 16, 2006
    #1
    1. Advertising

  2. Rob Williscroft, Oct 16, 2006
    #2
    1. Advertising

  3. abcd

    abcd Guest

    abcd, Oct 16, 2006
    #3
  4. On Mon, 16 Oct 2006 07:26:05 -0700, abcd wrote:

    > class Foo:
    > def __init__(self, name, data=[]):


    The binding of the name "data" to the empty list happens at compile time,
    not runtime.

    > self.name = name
    > self.data = data
    >
    > def addData(self, val):
    > self.data.append(val)


    Every time you call addData on an instance, it appends to the same list.
    So all instances created with Foo(name) share the same list in data.

    Think of it like this:

    some_list = []
    x = Foo("fred", some_list)
    y = Foo("wilma", some_list)

    Isn't it obvious now that both instances share the same list? That x.data
    and y.data don't just have the same value, but are the same object? The
    same thing happens when you set the default.


    > f = Foo('a')
    > f.addData(1)
    > f.addData(2)
    >
    > f2 = Foo('b', [])


    And in this case, you've passed a DIFFERENT empty list as an argument.


    The normal Python way for handling this situation is to not use mutable
    objects as defaults unless you want this behaviour. Instead, use None as
    the default value:

    class Foo:
    def __init__(self, name, data=None):
    self.name = name
    if data is None: self.data = []
    else: self.data = data


    > Any ideas? is this a bug?


    Well, it's a bug in your code :)

    It isn't a bug in Python. At worst, it is a "gotcha", but it is a
    deliberate design decision, and quite useful. For example, this is good
    for caching complicated calculations:

    def function(x, _cache={}):
    # _cache is initialised to an empty dictionary at compile time
    if _cache.has_key(x):
    return _cache[x]
    else:
    # complicated and time consuming calculation happens
    _cache[x] = result
    return result




    --
    Steven.
     
    Steven D'Aprano, Oct 16, 2006
    #4
  5. abcd

    Paul Rubin Guest

    Steven D'Aprano <> writes:
    > It isn't a bug in Python. At worst, it is a "gotcha", but it is a
    > deliberate design decision, and quite useful. For example, this is good
    > for caching complicated calculations:
    >
    > def function(x, _cache={}):
    > # _cache is initialised to an empty dictionary at compile time
    > if _cache.has_key(x):
    > return _cache[x]


    The above can be done explicitly:

    def function(x):
    if function._cache.has_key(x):
    return function._cache[x]
    ...
    # function gets an initially-empty cache
    function._cache = {}

    So the existing behavior, while not a bug (since it's documented), may
    well be a wart.
     
    Paul Rubin, Oct 16, 2006
    #5
  6. abcd

    Neil Cerutti Guest

    On 2006-10-16, Steven D'Aprano
    <> wrote:
    > Well, it's a bug in your code :)
    >
    > It isn't a bug in Python. At worst, it is a "gotcha", but it is
    > a deliberate design decision, and quite useful. For example,
    > this is good for caching complicated calculations:


    I'd say the feature is "usable" rather than "useful", like
    bitfields in C.

    --
    Neil Cerutti
    Next Sunday Mrs. Vinson will be soloist for the morning service.
    The pastor will then speak on "It's a Terrible Experience."
    --Church Bulletin Blooper
     
    Neil Cerutti, Oct 16, 2006
    #6
  7. Steven D'Aprano wrote:

    > It isn't a bug in Python. At worst, it is a "gotcha", but it is a
    > deliberate design decision, and quite useful. For example, this is good
    > for caching complicated calculations:


    it's also used to pass in *objects* instead of names into an inner scope.

    </F>
     
    Fredrik Lundh, Oct 16, 2006
    #7
  8. abcd wrote:

    > Rob Williscroft wrote:
    >> http://docs.python.org/ref/function.html#l2h-619

    >
    >
    > thanks. weird that it works that way since they even state "This is
    > generally not what was intended."


    The "not intended" refers to the programmer making the mistake of creating a
    shared instance - which usually isn't intended, as you yourself are an
    example of.

    Diez
     
    Diez B. Roggisch, Oct 16, 2006
    #8
  9. On Mon, 2006-10-16 at 10:51, Steven D'Aprano wrote:
    > On Mon, 16 Oct 2006 07:26:05 -0700, abcd wrote:
    >
    > > class Foo:
    > > def __init__(self, name, data=[]):

    >
    > The binding of the name "data" to the empty list happens at compile time,
    > not runtime.


    I think this statement needs to be clarified. The binding of "data" to
    the empty list *does* happen at runtime, not at compile time. However,
    the binding happens only once, when the "def" statement is executed, as
    opposed to every time the __init__ function is called.

    -Carsten
     
    Carsten Haese, Oct 16, 2006
    #9
  10. Carsten Haese wrote:

    > I think this statement needs to be clarified. The binding of "data" to
    > the empty list *does* happen at runtime, not at compile time. However,
    > the binding happens only once, when the "def" statement is executed, as
    > opposed to every time the __init__ function is called.


    to be precise, it happens every time the "def" statement is executed.

    </F>
     
    Fredrik Lundh, Oct 16, 2006
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sstark
    Replies:
    0
    Views:
    472
    sstark
    Mar 6, 2005
  2. ryang
    Replies:
    1
    Views:
    974
    Wes Groleau
    Apr 11, 2005
  3. Apogee

    Strange Behavior with ViewState

    Apogee, Jul 3, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    336
    Apogee
    Jul 3, 2003
  4. PJ

    DropDownList Strange Behavior

    PJ, Jul 8, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    357
  5. Mantorok Redgormor
    Replies:
    70
    Views:
    1,824
    Dan Pop
    Feb 17, 2004
Loading...

Share This Page