class attribute confusion

Discussion in 'Python' started by OAN, Dec 3, 2010.

  1. OAN

    OAN Guest

    Hi,

    i was having a problem with class attributes initiated outside of
    __init__. This code is a demonstration of what i mean:

    class A():
    mylist = []
    def __init__(self):
    self.mylist.append(1)
    pass

    class B(A):
    def __init__(self):
    A.__init__(self)
    self.mylist.append(2)

    v = A()
    print 'v:',v.mylist
    x = B()
    print 'x:',x.mylist
    y = B()
    print 'y:',y.mylist
    z = A()
    print 'z:',z.mylist
    print 'v:',v.mylist

    I would expect the following result:

    v: [1]
    x: [1, 2]
    y: [1, 2]
    z: [1]
    v: [1]

    Who wouldn't, right? But actually python 2.6(.6) gives me the following
    result:

    v: [1]
    x: [1, 1, 2]
    y: [1, 1, 2, 1, 2]
    z: [1, 1, 2, 1, 2, 1]
    v: [1, 1, 2, 1, 2, 1]

    The four variables v,x,y and z now actually share the same 'mylist'!! To
    get the correct results, i have to initialize 'mylist' inside of the
    __init__ method!

    I think this behaviour is totally wrong, since it seems A.__init__(self)
    is changing the value inside of A() not inside of the object variable
    'self' (that should be x or y)!!


    Could someone explain this to me, please?

    regards.
     
    OAN, Dec 3, 2010
    #1
    1. Advertising

  2. OAN <> writes:

    > Hi,
    >
    > i was having a problem with class attributes initiated outside of
    > __init__. This code is a demonstration of what i mean:
    >
    > class A():
    > mylist = []
    > def __init__(self):
    > self.mylist.append(1)
    > pass
    >
    > class B(A):
    > def __init__(self):
    > A.__init__(self)
    > self.mylist.append(2)
    >
    > v = A()
    > print 'v:',v.mylist
    > x = B()
    > print 'x:',x.mylist
    > y = B()
    > print 'y:',y.mylist
    > z = A()
    > print 'z:',z.mylist
    > print 'v:',v.mylist
    >
    > I would expect the following result:
    >
    > v: [1]
    > x: [1, 2]
    > y: [1, 2]
    > z: [1]
    > v: [1]
    >
    > Who wouldn't, right? But actually python 2.6(.6) gives me the
    > following result:
    >
    > v: [1]
    > x: [1, 1, 2]
    > y: [1, 1, 2, 1, 2]
    > z: [1, 1, 2, 1, 2, 1]
    > v: [1, 1, 2, 1, 2, 1]
    >
    > The four variables v,x,y and z now actually share the same 'mylist'!!
    > To get the correct results, i have to initialize 'mylist' inside of
    > the __init__ method!


    Yes. See below.

    > I think this behaviour is totally wrong, since it seems
    > A.__init__(self) is changing the value inside of A() not inside of the
    > object variable 'self' (that should be x or y)!!


    It's not wrong at all. You expect "mylist" to behave as an instance
    attribute, but you defined it as a class attribute. Instance attributes
    are naturally initialised in the __init__() method.

    --
    Arnaud
     
    Arnaud Delobelle, Dec 3, 2010
    #2
    1. Advertising

  3. On Fri, 03 Dec 2010 22:54:19 +0100, OAN wrote:

    > Hi,
    >
    > i was having a problem with class attributes initiated outside of
    > __init__. This code is a demonstration of what i mean:

    [...]
    > I would expect the following result:
    >
    > v: [1]
    > x: [1, 2]
    > y: [1, 2]
    > z: [1]
    > v: [1]
    >
    > Who wouldn't, right?


    Everybody who actually understands Python's object model.


    > The four variables v,x,y and z now actually share the same 'mylist'!! To
    > get the correct results, i have to initialize 'mylist' inside of the
    > __init__ method!


    Right. If you define a *class* attribute, it lives in the class, not the
    instance, and so all instances share the same value.

    > I think this behaviour is totally wrong, since it seems A.__init__(self)
    > is changing the value inside of A() not inside of the object variable
    > 'self' (that should be x or y)!!


    A.__init__(self) calls A's init method with self (either x or y) as the
    self parameter, but A's init method merely modifies the class attribute
    mylist in place. It doesn't create a new list.

    The behaviour you're seeing is no different from this:

    shared = []
    a = {"spam": shared, "ham": 23}
    b = {"spam": shared, "ham": 42}
    a["spam"].append("parrot")

    What would you expect the value of b["spam"] to be?


    --
    Steven
     
    Steven D'Aprano, Dec 3, 2010
    #3
  4. Am 03.12.2010 23:11, schrieb Arnaud Delobelle:
    > OAN<> writes:
    >
    >> Hi,
    >>
    >> i was having a problem with class attributes initiated outside of
    >> __init__. This code is a demonstration of what i mean:
    >>
    >> class A():
    >> mylist = []
    >> def __init__(self):
    >> self.mylist.append(1)
    >> pass
    >>
    >> class B(A):
    >> def __init__(self):
    >> A.__init__(self)
    >> self.mylist.append(2)
    >>
    >> v = A()
    >> print 'v:',v.mylist
    >> x = B()
    >> print 'x:',x.mylist
    >> y = B()
    >> print 'y:',y.mylist
    >> z = A()
    >> print 'z:',z.mylist
    >> print 'v:',v.mylist
    >>
    >> I would expect the following result:
    >>
    >> v: [1]
    >> x: [1, 2]
    >> y: [1, 2]
    >> z: [1]
    >> v: [1]
    >>
    >> Who wouldn't, right? But actually python 2.6(.6) gives me the
    >> following result:
    >>
    >> v: [1]
    >> x: [1, 1, 2]
    >> y: [1, 1, 2, 1, 2]
    >> z: [1, 1, 2, 1, 2, 1]
    >> v: [1, 1, 2, 1, 2, 1]
    >>
    >> The four variables v,x,y and z now actually share the same 'mylist'!!
    >> To get the correct results, i have to initialize 'mylist' inside of
    >> the __init__ method!

    > Yes. See below.
    >
    >> I think this behaviour is totally wrong, since it seems
    >> A.__init__(self) is changing the value inside of A() not inside of the
    >> object variable 'self' (that should be x or y)!!

    > It's not wrong at all. You expect "mylist" to behave as an instance
    > attribute, but you defined it as a class attribute. Instance attributes
    > are naturally initialised in the __init__() method.
    >

    Could you please point me to a reference in the doc??

    Thanks in advance.
     
    Omar Abo-Namous, Dec 4, 2010
    #4
  5. On Sat, 04 Dec 2010 15:00:43 +0100, Omar Abo-Namous wrote:

    >>> I think this behaviour is totally wrong, since it seems
    >>> A.__init__(self) is changing the value inside of A() not inside of the
    >>> object variable 'self' (that should be x or y)!!

    >> It's not wrong at all. You expect "mylist" to behave as an instance
    >> attribute, but you defined it as a class attribute. Instance
    >> attributes are naturally initialised in the __init__() method.
    >>

    > Could you please point me to a reference in the doc??


    http://docs.python.org/reference/datamodel.html

    In the section about classes:

    "Class attribute assignments update the class’s dictionary ..."

    and in the section about class instances:

    "Attribute assignments and deletions update the instance’s dictionary,
    never a class’s dictionary."

    In this specific example, you also have to realise that mylist.append()
    mutates the list in place, and doesn't create a new list. It doesn't
    matter whether the list comes from a global variable, a local variable,
    an instance attribute or a class attribute, append is always an inplace
    operation.


    --
    Steven
     
    Steven D'Aprano, Dec 4, 2010
    #5
  6. OAN

    Steve Holden Guest

    On 12/3/2010 11:58 PM, Steven D'Aprano wrote:
    > Right. If you define a *class* attribute, it lives in the class, not the
    > instance, and so all instances share the same value.


    Unless, of course, an instance binds the same name in its namespace, in
    which case it will (usually) mask the class attribute for that instance.

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    PyCon 2011 Atlanta March 9-17 http://us.pycon.org/
    See Python Video! http://python.mirocommunity.org/
    Holden Web LLC http://www.holdenweb.com/
     
    Steve Holden, Dec 6, 2010
    #6
    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. Jordan Willms
    Replies:
    2
    Views:
    856
    Richard Tobin
    Nov 9, 2004
  2. Donnal Walter

    class attribute to instance attribute

    Donnal Walter, Jun 30, 2005, in forum: Python
    Replies:
    4
    Views:
    509
    Greg Ewing
    Jul 6, 2005
  3. Kent Johnson
    Replies:
    5
    Views:
    285
    Kent Johnson
    Nov 14, 2005
  4. Russell Warren
    Replies:
    5
    Views:
    493
    Russell Warren
    Jan 17, 2006
  5. 陈伟
    Replies:
    9
    Views:
    278
    Hans Mulder
    Aug 30, 2012
Loading...

Share This Page