Unclear On Class Variables

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tim Daneliuk

    #1

    Unclear On Class Variables

    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 tundra@tundrawa re.com
    PGP Key: http://www.tundraware.com/PGP/
  • Diez B. Roggisch

    #2
    Re: Unclear On Class Variables

    Tim Daneliuk wrote:
    [color=blue]
    > 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 ...[/color]

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

    --
    Regards,

    Diez B. Roggisch

    Comment

    • Simon Brunning

      #3
      Re: Unclear On Class Variables

      On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <tundra@tundraw are.com> wrote:[color=blue]
      > 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.[/color]

      I can see why you might think that:
      [color=blue][color=green][color=darkred]
      >>> class Spam(object):[/color][/color][/color]
      .... eggs = 4
      ....[color=blue][color=green][color=darkred]
      >>> spam = Spam()
      >>> spam2 = Spam()
      >>> spam.eggs[/color][/color][/color]
      4[color=blue][color=green][color=darkred]
      >>> spam2.eggs[/color][/color][/color]
      4[color=blue][color=green][color=darkred]
      >>> spam.eggs = 2
      >>> spam.eggs[/color][/color][/color]
      2[color=blue][color=green][color=darkred]
      >>> spam2.eggs[/color][/color][/color]
      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:
      [color=blue][color=green][color=darkred]
      >>> class Spam(object):[/color][/color][/color]
      .... eggs = [3]
      ....[color=blue][color=green][color=darkred]
      >>> spam = Spam()
      >>> spam2 = Spam()
      >>> spam.eggs[/color][/color][/color]
      [3][color=blue][color=green][color=darkred]
      >>> spam2.eggs[/color][/color][/color]
      [3][color=blue][color=green][color=darkred]
      >>> spam.eggs.appen d(5)
      >>> spam.eggs[/color][/color][/color]
      [3, 5][color=blue][color=green][color=darkred]
      >>> spam2.eggs[/color][/color][/color]
      [3, 5]

      --
      Cheers,
      Simon B,
      simon@brunningo nline.net,

      Comment

      • harold fellermann

        #4
        Re: Unclear On Class Variables

        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:
        [color=blue][color=green][color=darkred]
        >>> foo = Foo()
        >>> foo.x += 1
        >>>
        >>> print foo.x[/color][/color][/color]
        1[color=blue][color=green][color=darkred]
        >>> print Foo.x[/color][/color][/color]
        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:
        [color=blue]
        > 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 tundra@tundrawa re.com
        > PGP Key: http://www.tundraware.com/PGP/
        > --
        > http://mail.python.org/mailman/listinfo/python-list
        >
        >[/color]
        --
        Everyone is a genius.
        It's just that some people are too stupid to realize it.

        Comment

        • Antoon Pardon

          #5
          Re: Unclear On Class Variables

          Op 2005-01-13, Simon Brunning schreef <simon.brunning @gmail.com>:[color=blue]
          > On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <tundra@tundraw are.com> wrote:[color=green]
          >> 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.[/color]
          >
          > I can see why you might think that:
          >[color=green][color=darkred]
          >>>> class Spam(object):[/color][/color]
          > ... eggs = 4
          > ...[color=green][color=darkred]
          >>>> spam = Spam()
          >>>> spam2 = Spam()
          >>>> spam.eggs[/color][/color]
          > 4[color=green][color=darkred]
          >>>> spam2.eggs[/color][/color]
          > 4[color=green][color=darkred]
          >>>> spam.eggs = 2
          >>>> spam.eggs[/color][/color]
          > 2[color=green][color=darkred]
          >>>> spam2.eggs[/color][/color]
          > 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:
          >[color=green][color=darkred]
          >>>> class Spam(object):[/color][/color]
          > ... eggs = [3]
          > ...[color=green][color=darkred]
          >>>> spam = Spam()
          >>>> spam2 = Spam()
          >>>> spam.eggs[/color][/color]
          > [3][color=green][color=darkred]
          >>>> spam2.eggs[/color][/color]
          > [3][color=green][color=darkred]
          >>>> spam.eggs.appen d(5)
          >>>> spam.eggs[/color][/color]
          > [3, 5][color=green][color=darkred]
          >>>> spam2.eggs[/color][/color]
          > [3, 5]
          >[/color]

          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

          Comment

          • Antoon Pardon

            #6
            Re: Unclear On Class Variables

            Op 2005-01-13, harold fellermann schreef <harold.fellerm ann@upf.edu>:[color=blue]
            > 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:
            >[color=green][color=darkred]
            > >>> foo = Foo()
            > >>> foo.x += 1
            > >>>
            > >>> print foo.x[/color][/color]
            > 1[color=green][color=darkred]
            > >>> print Foo.x[/color][/color]
            > 0
            >
            > although the += operator looks like an inplace add it isn't.
            > it is just syntactic sugar for foo.x = foo.x + 1.[/color]

            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

            Comment

            • Peter Hansen

              #7
              Re: Unclear On Class Variables

              Simon Brunning wrote:[color=blue]
              > On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <tundra@tundraw are.com> 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:[/color]

              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:
              [color=blue][color=green][color=darkred]
              >>> class Spam(object):[/color][/color][/color]
              .... eggs = [3]
              ....[color=blue][color=green][color=darkred]
              >>> spam = Spam()
              >>> spam2 = Spam()
              >>> spam.eggs = [7]
              >>> spam2.eggs[/color][/color][/color]
              [3]

              -Peter

              Comment

              • Simon Brunning

                #8
                Re: Unclear On Class Variables

                On Thu, 13 Jan 2005 08:56:10 -0500, Peter Hansen <peter@engcorp. com> wrote:[color=blue]
                > Simon, it's really not about mutability at all. You've changed
                > the example,[/color]

                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,
                simon@brunningo nline.net,

                Comment

                • Antoon Pardon

                  #9
                  Re: Unclear On Class Variables

                  >[color=blue]
                  > 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.[/color]

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

                  Comment

                  • Steve Holden

                    #10
                    Re: Unclear On Class Variables

                    Tim Daneliuk wrote:
                    [color=blue]
                    > 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.[/color]

                    What it actually does is define names with the given values *in the
                    class namespace*.
                    [color=blue]
                    > 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.
                    >[/color]
                    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.
                    [color=blue]
                    > It is late and I am probably missing the obvious. Enlightenment
                    > appreciated ...[/color]

                    You can refer to class variables using the class name explicitly, both
                    within methods and externally:
                    [color=blue][color=green][color=darkred]
                    >>> class X:[/color][/color][/color]
                    ... count = 0
                    ... def getCt(self):
                    ... return self.count
                    ... def inc(self):
                    ... self.count += 1
                    ...[color=blue][color=green][color=darkred]
                    >>> x1 = X()
                    >>> x2 = X()
                    >>> id(x1.count)[/color][/color][/color]
                    168378284[color=blue][color=green][color=darkred]
                    >>> x1.inc()
                    >>> id(x1.count)[/color][/color][/color]
                    168378272[color=blue][color=green][color=darkred]
                    >>> id(x2.count)[/color][/color][/color]
                    168378284[color=blue][color=green][color=darkred]
                    >>> id(X.count)[/color][/color][/color]
                    168378284[color=blue][color=green][color=darkred]
                    >>> x1.getCt()[/color][/color][/color]
                    1[color=blue][color=green][color=darkred]
                    >>> x2.getCt()[/color][/color][/color]
                    0[color=blue][color=green][color=darkred]
                    >>>[/color][/color][/color]

                    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

                    Comment

                    • Fredrik Lundh

                      #11
                      Re: Unclear On Class Variables

                      Tim Daneliuk wrote:
                      [color=blue]
                      >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.[/color]

                      "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.
                      [color=blue][color=green][color=darkred]
                      >>> class foo(object):[/color][/color][/color]
                      .... x = 0
                      .... y = 1
                      ....[color=blue][color=green][color=darkred]
                      >>> obj = foo()
                      >>> obj.__dict__[/color][/color][/color]
                      {}[color=blue][color=green][color=darkred]
                      >>> obj.x[/color][/color][/color]
                      0[color=blue][color=green][color=darkred]
                      >>> obj.y[/color][/color][/color]
                      1[color=blue][color=green][color=darkred]
                      >>> foo.x[/color][/color][/color]
                      0[color=blue][color=green][color=darkred]
                      >>> obj.x = 10
                      >>> obj.__dict__[/color][/color][/color]
                      {'x': 10}[color=blue][color=green][color=darkred]
                      >>> obj.x[/color][/color][/color]
                      10[color=blue][color=green][color=darkred]
                      >>> foo.x[/color][/color][/color]
                      0

                      if you want to assign to the class variable, assign to the class variable:
                      [color=blue][color=green][color=darkred]
                      >>> obj = foo()
                      >>> obj.x[/color][/color][/color]
                      0[color=blue][color=green][color=darkred]
                      >>> foo.x = 20
                      >>> obj.__dict__[/color][/color][/color]
                      {}[color=blue][color=green][color=darkred]
                      >>> obj.x[/color][/color][/color]
                      20[color=blue][color=green][color=darkred]
                      >>> foo().x[/color][/color][/color]
                      20

                      </F>



                      Comment

                      • Pierre Barbier de Reuille

                        #12
                        Re: Unclear On Class Variables

                        Antoon Pardon a écrit :[color=blue][color=green]
                        >>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.[/color]
                        >
                        >
                        > 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
                        > --------------------
                        >[/color]

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

                        Pierre

                        Comment

                        • Pierre Barbier de Reuille

                          #13
                          Re: Unclear On Class Variables

                          Pierre Barbier de Reuille a écrit :[color=blue]
                          > Antoon Pardon a écrit :
                          >[color=green][color=darkred]
                          >>> 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.[/color]
                          >>
                          >>
                          >>
                          >> 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
                          >> --------------------
                          >>[/color]
                          >
                          > Well ... and could someone explain this behaviour ?
                          > I don't catch it !
                          >
                          > Pierre[/color]

                          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

                          Comment

                          Working...