FAQ
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.

Search Discussions

  • Arnaud Delobelle at Dec 3, 2010 at 10:11 pm

    OAN <programming at toomuchcookies.net> 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
  • Omar Abo-Namous at Dec 4, 2010 at 2:00 pm

    Am 03.12.2010 23:11, schrieb Arnaud Delobelle:
    OAN<programming at toomuchcookies.net> 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.
  • Steven D'Aprano at Dec 4, 2010 at 2:34 pm

    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 at Dec 3, 2010 at 10:58 pm

    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
  • Steve Holden at Dec 6, 2010 at 6:58 am

    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/

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedDec 3, '10 at 9:54p
activeDec 6, '10 at 6:58a
posts6
users5
websitepython.org

People

Translate

site design / logo © 2022 Grokbase