Unclear On Class Variables

Discussion in 'Python' started by Tim Daneliuk, Jan 13, 2005.

  1. Tim Daneliuk

    Tim Daneliuk Guest

    I am a bit confused. I was under the impression that:

    class foo(object):
    x = 0
    y = 1

    means that x and y are variables shared by all instances of a class.
    But when I run this against two instances of foo, and set the values
    of x and y, they are indeed unique to the *instance* rather than the
    class.

    It is late and I am probably missing the obvious. Enlightenment appreciated ...
    --
    ----------------------------------------------------------------------------
    Tim Daneliuk
    PGP Key: http://www.tundraware.com/PGP/
     
    Tim Daneliuk, Jan 13, 2005
    #1
    1. Advertising

  2. Tim Daneliuk wrote:

    > I am a bit confused. I was under the impression that:
    >
    > class foo(object):
    > x = 0
    > y = 1
    >
    > means that x and y are variables shared by all instances of a class.
    > But when I run this against two instances of foo, and set the values
    > of x and y, they are indeed unique to the *instance* rather than the
    > class.
    >
    > It is late and I am probably missing the obvious. Enlightenment
    > appreciated ...


    Without actual code how you set the vars, no one can answer that question.

    --
    Regards,

    Diez B. Roggisch
     
    Diez B. Roggisch, Jan 13, 2005
    #2
    1. Advertising

  3. On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <> wrote:
    > I am a bit confused. I was under the impression that:
    >
    > class foo(object):
    > x = 0
    > y = 1
    >
    > means that x and y are variables shared by all instances of a class.
    > But when I run this against two instances of foo, and set the values
    > of x and y, they are indeed unique to the *instance* rather than the
    > class.


    I can see why you might think that:

    >>> class Spam(object):

    .... eggs = 4
    ....
    >>> spam = Spam()
    >>> spam2 = Spam()
    >>> spam.eggs

    4
    >>> spam2.eggs

    4
    >>> spam.eggs = 2
    >>> spam.eggs

    2
    >>> spam2.eggs

    4

    But you are being mislead by the fact that integers are immutable.
    'spam.eggs = 2' is *creating* an instance member - there wasn't one
    before. Have a look at what happens with a mutable object:

    >>> class Spam(object):

    .... eggs = [3]
    ....
    >>> spam = Spam()
    >>> spam2 = Spam()
    >>> spam.eggs

    [3]
    >>> spam2.eggs

    [3]
    >>> spam.eggs.append(5)
    >>> spam.eggs

    [3, 5]
    >>> spam2.eggs

    [3, 5]

    --
    Cheers,
    Simon B,
    ,
    http://www.brunningonline.net/simon/blog/
     
    Simon Brunning, Jan 13, 2005
    #3
  4. Hi Tim,

    If you have

    class Foo(object) :
    x = 0
    y = 1

    foo = Foo()

    foo.x # reads either instance or class attribute (class in this case)

    foo.x = val # sets an instance attribute (because foo is instance not
    class)

    Foo.x = val # sets a class attribute
    foo.__class.__x = val # does the same

    this might be sometimes confusing. IMHO, the following is especially
    nasty:

    >>> foo = Foo()
    >>> foo.x += 1
    >>>
    >>> print foo.x

    1
    >>> print Foo.x

    0

    although the += operator looks like an inplace add it isn't.
    it is just syntactic sugar for foo.x = foo.x + 1.


    - harold -


    On 13.01.2005, at 07:18, Tim Daneliuk wrote:

    > I am a bit confused. I was under the impression that:
    >
    > class foo(object):
    > x = 0
    > y = 1
    >
    > means that x and y are variables shared by all instances of a class.
    > But when I run this against two instances of foo, and set the values
    > of x and y, they are indeed unique to the *instance* rather than the
    > class.
    >
    > It is late and I am probably missing the obvious. Enlightenment
    > appreciated ...
    > --
    > -----------------------------------------------------------------------
    > -----
    > Tim Daneliuk
    > PGP Key: http://www.tundraware.com/PGP/
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >
    >

    --
    Everyone is a genius.
    It's just that some people are too stupid to realize it.
     
    harold fellermann, Jan 13, 2005
    #4
  5. Op 2005-01-13, Simon Brunning schreef <>:
    > On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <> wrote:
    >> I am a bit confused. I was under the impression that:
    >>
    >> class foo(object):
    >> x = 0
    >> y = 1
    >>
    >> means that x and y are variables shared by all instances of a class.
    >> But when I run this against two instances of foo, and set the values
    >> of x and y, they are indeed unique to the *instance* rather than the
    >> class.

    >
    > I can see why you might think that:
    >
    >>>> class Spam(object):

    > ... eggs = 4
    > ...
    >>>> spam = Spam()
    >>>> spam2 = Spam()
    >>>> spam.eggs

    > 4
    >>>> spam2.eggs

    > 4
    >>>> spam.eggs = 2
    >>>> spam.eggs

    > 2
    >>>> spam2.eggs

    > 4
    >
    > But you are being mislead by the fact that integers are immutable.
    > 'spam.eggs = 2' is *creating* an instance member - there wasn't one
    > before. Have a look at what happens with a mutable object:
    >
    >>>> class Spam(object):

    > ... eggs = [3]
    > ...
    >>>> spam = Spam()
    >>>> spam2 = Spam()
    >>>> spam.eggs

    > [3]
    >>>> spam2.eggs

    > [3]
    >>>> spam.eggs.append(5)
    >>>> spam.eggs

    > [3, 5]
    >>>> spam2.eggs

    > [3, 5]
    >


    Well I find this a confusing behaviour on python's part. The fact
    that instance.field can mean something different, depending on
    where in a statement you find it, makes the behaviour inconsistent.

    I know people in general here are against declarations, but declarations
    could IMO provide more consistency here and thus more obvious behaviour.

    --
    Antoon Pardon
     
    Antoon Pardon, Jan 13, 2005
    #5
  6. Op 2005-01-13, harold fellermann schreef <>:
    > Hi Tim,
    >
    > If you have
    >
    > class Foo(object) :
    > x = 0
    > y = 1
    >
    > foo = Foo()
    >
    > foo.x # reads either instance or class attribute (class in this case)
    >
    > foo.x = val # sets an instance attribute (because foo is instance not
    > class)
    >
    > Foo.x = val # sets a class attribute
    > foo.__class.__x = val # does the same
    >
    > this might be sometimes confusing. IMHO, the following is especially
    > nasty:
    >
    > >>> foo = Foo()
    > >>> foo.x += 1
    > >>>
    > >>> print foo.x

    > 1
    > >>> print Foo.x

    > 0
    >
    > although the += operator looks like an inplace add it isn't.
    > it is just syntactic sugar for foo.x = foo.x + 1.


    Except is x belongs to a mutable class that implements the
    += operator as an inplace add.

    Try the same but with x = [2]
    and foo.x += [3]

    --
    Antoon Pardon
     
    Antoon Pardon, Jan 13, 2005
    #6
  7. Tim Daneliuk

    Peter Hansen Guest

    Simon Brunning wrote:
    > On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <> wrote:
    > But you are being mislead by the fact that integers are immutable.
    > 'spam.eggs = 2' is *creating* an instance member - there wasn't one
    > before. Have a look at what happens with a mutable object:


    Simon, it's really not about mutability at all. You've changed
    the example, which was binding a name (specifically setting an
    attribute), to one in which you are simply calling a method on
    the object. If you change your example to bind the name the
    same way, even with a mutable, it will work the same way as Tim's
    original did with integers:

    >>> class Spam(object):

    .... eggs = [3]
    ....
    >>> spam = Spam()
    >>> spam2 = Spam()
    >>> spam.eggs = [7]
    >>> spam2.eggs

    [3]

    -Peter
     
    Peter Hansen, Jan 13, 2005
    #7
  8. On Thu, 13 Jan 2005 08:56:10 -0500, Peter Hansen <> wrote:
    > Simon, it's really not about mutability at all. You've changed
    > the example,


    Err, there *wasn't* an example, not really. The OP just mentioned
    'setting the values' of instance members. That *can* mean name
    binding, but (to my mind at least) it can also mean calling mutating
    methods. I just wanted to show both.

    --
    Cheers,
    Simon B,
    ,
    http://www.brunningonline.net/simon/blog/
     
    Simon Brunning, Jan 13, 2005
    #8
  9. >
    > Well I find this a confusing behaviour on python's part. The fact
    > that instance.field can mean something different, depending on
    > where in a statement you find it, makes the behaviour inconsistent.
    >
    > I know people in general here are against declarations, but declarations
    > could IMO provide more consistency here and thus more obvious behaviour.


    Well just to show how confusing python can be, the following piece of
    code.

    | class Spam:
    | eggs = [2, 3]
    |
    |
    | sp1 = Spam()
    | sp2 = Spam()
    |
    | print sp1.eggs, id(sp1.eggs)
    | print sp2.eggs, id(sp2.eggs)
    | print '--------------------'
    |
    | sp1.eggs += [4,]
    |
    | print sp1.eggs, id(sp1.eggs)
    | print sp2.eggs, id(sp2.eggs)
    | print '--------------------'
    |
    | Spam.eggs = [3,5]
    |
    | print sp1.eggs, id(sp1.eggs)
    | print sp2.eggs, id(sp2.eggs)
    | print '--------------------'

    Which produces:

    [2, 3] 1075958860
    [2, 3] 1075958860
    --------------------
    [2, 3, 4] 1075958860
    [2, 3, 4] 1075958860
    --------------------
    [2, 3, 4] 1075958860
    [3, 5] 1075959084
    --------------------
     
    Antoon Pardon, Jan 13, 2005
    #9
  10. Tim Daneliuk

    Steve Holden Guest

    Tim Daneliuk wrote:

    > I am a bit confused. I was under the impression that:
    >
    > class foo(object):
    > x = 0
    > y = 1
    >
    > means that x and y are variables shared by all instances of a class.


    What it actually does is define names with the given values *in the
    class namespace*.

    > But when I run this against two instances of foo, and set the values
    > of x and y, they are indeed unique to the *instance* rather than the
    > class.
    >

    I imagine here you are setting instance variables, which then *mask* the
    presence of class variables with the same name, because "self-relative"
    name resolution looks in the instance namespace before it looks in the
    class namespace.

    > It is late and I am probably missing the obvious. Enlightenment
    > appreciated ...


    You can refer to class variables using the class name explicitly, both
    within methods and externally:

    >>> class X:

    ... count = 0
    ... def getCt(self):
    ... return self.count
    ... def inc(self):
    ... self.count += 1
    ...
    >>> x1 = X()
    >>> x2 = X()
    >>> id(x1.count)

    168378284
    >>> x1.inc()
    >>> id(x1.count)

    168378272
    >>> id(x2.count)

    168378284
    >>> id(X.count)

    168378284
    >>> x1.getCt()

    1
    >>> x2.getCt()

    0
    >>>


    regards
    Steve
    --
    Steve Holden http://www.holdenweb.com/
    Python Web Programming http://pydish.holdenweb.com/
    Holden Web LLC +1 703 861 4237 +1 800 494 3119
     
    Steve Holden, Jan 13, 2005
    #10
  11. Tim Daneliuk wrote:

    >I am a bit confused. I was under the impression that:
    >
    > class foo(object):
    > x = 0
    > y = 1
    >
    > means that x and y are variables shared by all instances of a class.
    > But when I run this against two instances of foo, and set the values
    > of x and y, they are indeed unique to the *instance* rather than the
    > class.


    "set" as in:

    obj = foo()
    obj.x = 10 # set x

    ?

    if so, the "obj.x=" line is *adding* an instance variable to the "x" object, which will
    then hide the "x" at the class level.

    >>> class foo(object):

    .... x = 0
    .... y = 1
    ....
    >>> obj = foo()
    >>> obj.__dict__

    {}
    >>> obj.x

    0
    >>> obj.y

    1
    >>> foo.x

    0
    >>> obj.x = 10
    >>> obj.__dict__

    {'x': 10}
    >>> obj.x

    10
    >>> foo.x

    0

    if you want to assign to the class variable, assign to the class variable:

    >>> obj = foo()
    >>> obj.x

    0
    >>> foo.x = 20
    >>> obj.__dict__

    {}
    >>> obj.x

    20
    >>> foo().x

    20

    </F>
     
    Fredrik Lundh, Jan 13, 2005
    #11
  12. Antoon Pardon a écrit :
    >>Well I find this a confusing behaviour on python's part. The fact
    >>that instance.field can mean something different, depending on
    >>where in a statement you find it, makes the behaviour inconsistent.
    >>
    >>I know people in general here are against declarations, but declarations
    >>could IMO provide more consistency here and thus more obvious behaviour.

    >
    >
    > Well just to show how confusing python can be, the following piece of
    > code.
    >
    > | class Spam:
    > | eggs = [2, 3]
    > |
    > |
    > | sp1 = Spam()
    > | sp2 = Spam()
    > |
    > | print sp1.eggs, id(sp1.eggs)
    > | print sp2.eggs, id(sp2.eggs)
    > | print '--------------------'
    > |
    > | sp1.eggs += [4,]
    > |
    > | print sp1.eggs, id(sp1.eggs)
    > | print sp2.eggs, id(sp2.eggs)
    > | print '--------------------'
    > |
    > | Spam.eggs = [3,5]
    > |
    > | print sp1.eggs, id(sp1.eggs)
    > | print sp2.eggs, id(sp2.eggs)
    > | print '--------------------'
    >
    > Which produces:
    >
    > [2, 3] 1075958860
    > [2, 3] 1075958860
    > --------------------
    > [2, 3, 4] 1075958860
    > [2, 3, 4] 1075958860
    > --------------------
    > [2, 3, 4] 1075958860
    > [3, 5] 1075959084
    > --------------------
    >


    Well ... and could someone explain this behaviour ?
    I don't catch it !

    Pierre
     
    Pierre Barbier de Reuille, Jan 14, 2005
    #12
  13. Pierre Barbier de Reuille a écrit :
    > Antoon Pardon a écrit :
    >
    >>> Well I find this a confusing behaviour on python's part. The fact
    >>> that instance.field can mean something different, depending on
    >>> where in a statement you find it, makes the behaviour inconsistent.
    >>>
    >>> I know people in general here are against declarations, but declarations
    >>> could IMO provide more consistency here and thus more obvious behaviour.

    >>
    >>
    >>
    >> Well just to show how confusing python can be, the following piece of
    >> code.
    >>
    >> | class Spam:
    >> | eggs = [2, 3]
    >> | | | sp1 = Spam()
    >> | sp2 = Spam()
    >> | | print sp1.eggs, id(sp1.eggs)
    >> | print sp2.eggs, id(sp2.eggs)
    >> | print '--------------------'
    >> | | sp1.eggs += [4,]
    >> |
    >> | print sp1.eggs, id(sp1.eggs)
    >> | print sp2.eggs, id(sp2.eggs)
    >> | print '--------------------'
    >> |
    >> | Spam.eggs = [3,5]
    >> |
    >> | print sp1.eggs, id(sp1.eggs)
    >> | print sp2.eggs, id(sp2.eggs)
    >> | print '--------------------'
    >>
    >> Which produces:
    >>
    >> [2, 3] 1075958860
    >> [2, 3] 1075958860
    >> --------------------
    >> [2, 3, 4] 1075958860
    >> [2, 3, 4] 1075958860
    >> --------------------
    >> [2, 3, 4] 1075958860
    >> [3, 5] 1075959084
    >> --------------------
    >>

    >
    > Well ... and could someone explain this behaviour ?
    > I don't catch it !
    >
    > Pierre


    Ok, I think I got it ! I speak with friends working with Python too ...
    It seems that "a += l" if "a" and "l" are lists is equivalent to :

    a.extend(l)
    a = a

    The second line could seem meaningless but it is not ! Indeed, in the
    example above, the first "sp1.eggs" (the one with the extend) is a class
    variable but, the second "sp1.eggs" (the one before the "=") is an
    instance variable !

    So, at the end, we append to get sp1.eggs and Spam.eggs references to
    the same structure. But sp1.eggs is an instance variable of sp1 and no
    more the class variable. To test that, it's possible to modify slightly
    the code with :

    |sp1.eggs += [4,]
    |del sp1.eggs

    Then, sp1.eggs still exists !!! But it's again the class variable ...

    Ok, back to the documentation ...

    In the doc, there is a special case for the use of "+=" with the class
    members. IMHO, this should not be !!! But, it says that :

    ob.a += b

    is translated into :

    ob.__setattr__( "a", ob.__getattr__("a").__iadd__(b) )

    My opinion is : it would be much more simpler to explain than :

    a += b <=> a.__iadd__(b); a = a

    and not give any special case for class members. In both cases, the
    resulting behaviour is the same, but it would be less confusing.

    Then, this change of scope of variables in python is very very annoying.
    Both for new and old programmers (we have both in my lab ...).

    Well, I hope I got it write this time ... but this is a feature to fear !!!

    Pierre
     
    Pierre Barbier de Reuille, Jan 14, 2005
    #13
    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. kj
    Replies:
    2
    Views:
    361
    Patrick TJ McPhee
    Apr 12, 2004
  2. Shmuel (Seymour J.) Metz

    Scope of news group? Charter unclear

    Shmuel (Seymour J.) Metz, Jul 9, 2004, in forum: XML
    Replies:
    1
    Views:
    351
    Martin Honnen
    Jul 9, 2004
  3. Owen Jacobson

    Unclear on either EJB3 or JBoss or both

    Owen Jacobson, Jul 21, 2006, in forum: Java
    Replies:
    0
    Views:
    344
    Owen Jacobson
    Jul 21, 2006
  4. Eirik WS

    A few things remain unclear...

    Eirik WS, Feb 2, 2004, in forum: C Programming
    Replies:
    9
    Views:
    391
    Mark McIntyre
    Feb 3, 2004
  5. rtilley
    Replies:
    1
    Views:
    371
    Dennis Lee Bieber
    Nov 15, 2005
Loading...

Share This Page