Class Variable Access and Assignment

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

    Class Variable Access and Assignment

    This has to do with class variables and instances variables.

    Given the following:

    <code>

    class _class:
    var = 0
    #rest of the class

    instance_b = _class()

    _class.var=5

    print instance_b.var # -> 5
    print _class.var # -> 5

    </code>

    Initially this seems to make sense, note the difference between to last
    two lines, one is refering to the class variable 'var' via the class
    while the other refers to it via an instance.

    However if one attempts the following:

    <code>

    instance_b.var = 1000 # -> _class.var = 5
    _class.var = 9999 # -> _class.var = 9999

    </code>

    An obvious error occurs. When attempting to assign the class variable
    via the instance it instead creates a new entry in that instance's
    __dict__ and gives it the value. While this is allowed because of
    pythons ability to dynamically add attributes to a instance however it
    seems incorrect to have different behavior for different operations.

    There are two possible fixes, either by prohibiting instance variables
    with the same name as class variables, which would allow any reference
    to an instance of the class assign/read the value of the variable. Or
    to only allow class variables to be accessed via the class name itself.

    Many thanks to elpargo and coke. elpargo assisted in fleshing out the
    best way to present this.

    perhaps this was intended, i was just wondering if anyone else had
    noticed it, and if so what form would you consider to be 'proper'
    either referring to class variables via the class itself or via
    instances of that class. Any response would be greatly appreciated.


    Graham

  • Steven D'Aprano

    #2
    Re: Class Variable Access and Assignment

    On Thu, 03 Nov 2005 01:43:32 -0800, Graham wrote:

    [snip]
    [color=blue]
    > print instance_b.var # -> 5
    > print _class.var # -> 5
    >
    > </code>
    >
    > Initially this seems to make sense, note the difference between to last
    > two lines, one is refering to the class variable 'var' via the class
    > while the other refers to it via an instance.[/color]

    That's not correct. The line instance_b.var is referring to an instance
    attribute. According to the usual Object Oriented model of inheritance, if
    the instance does not have an attribute, the class is searched next.

    So instance_b.var and _class.var are asking for two different things. The
    first says, "Search the instance for attribute var, then the class." The
    second says "Search the class."

    BTW, a leading underscore is the convention for a private(ish) variable.
    The convention for naming a variable after a reserved word is a trailing
    underscore class_. In this case, there is also the convention that classes
    should start with a capital, so you have Class and instance. (instance, of
    course, is not a reserved word.)

    [color=blue]
    > However if one attempts the following:
    >
    > <code>
    >
    > instance_b.var = 1000 # -> _class.var = 5
    > _class.var = 9999 # -> _class.var = 9999
    >
    > </code>
    >
    > An obvious error occurs.[/color]

    I see no error. No exception is raised when I try it: I get the expected
    results. Assigning to an instance assigns to the instance, assigning to
    the class assigns to the class. That's normal OO behaviour.

    [color=blue]
    > When attempting to assign the class variable
    > via the instance it instead creates a new entry in that instance's
    > __dict__ and gives it the value.[/color]

    You might *want* to assign to the class attribute, but that's not what you
    are doing. You are assigning to the instance.

    Admittedly, it might not be the behaviour you expect, but it is the
    standard behaviour in (as far as I know) all OO languages.

    If you want to assign to the class attribute, you either assign to the
    class directly, or use instance_b.__cl ass__.var.

    [color=blue]
    > While this is allowed because of
    > pythons ability to dynamically add attributes to a instance however it
    > seems incorrect to have different behavior for different operations.[/color]

    Surely you can't mean that? Why would you want different operations to
    have the same behaviour?

    [color=blue]
    > There are two possible fixes, either by prohibiting instance variables
    > with the same name as class variables, which would allow any reference
    > to an instance of the class assign/read the value of the variable. Or
    > to only allow class variables to be accessed via the class name itself.[/color]

    There is also a third fix: understand Python's OO model, especially
    inheritance, so that normal behaviour no longer surprises you.


    --
    Steven.

    Comment

    • Antoon Pardon

      #3
      Re: Class Variable Access and Assignment

      Op 2005-11-03, Steven D'Aprano schreef <steve@REMOVETH IScyber.com.au> :
      [color=blue][color=green]
      >> There are two possible fixes, either by prohibiting instance variables
      >> with the same name as class variables, which would allow any reference
      >> to an instance of the class assign/read the value of the variable. Or
      >> to only allow class variables to be accessed via the class name itself.[/color]
      >
      > There is also a third fix: understand Python's OO model, especially
      > inheritance, so that normal behaviour no longer surprises you.[/color]

      No matter wat the OO model is, I don't think the following code
      exhibits sane behaviour:

      class A:
      a = 1

      b = A()
      b.a += 2
      print b.a
      print A.a

      Which results in

      3
      1

      --
      Antoon Pardon

      Comment

      • Stefan Arentz

        #4
        Re: Class Variable Access and Assignment

        Antoon Pardon <apardon@forel. vub.ac.be> writes:
        [color=blue]
        > Op 2005-11-03, Steven D'Aprano schreef <steve@REMOVETH IScyber.com.au> :
        >[color=green][color=darkred]
        > >> There are two possible fixes, either by prohibiting instance variables
        > >> with the same name as class variables, which would allow any reference
        > >> to an instance of the class assign/read the value of the variable. Or
        > >> to only allow class variables to be accessed via the class name itself.[/color]
        > >
        > > There is also a third fix: understand Python's OO model, especially
        > > inheritance, so that normal behaviour no longer surprises you.[/color]
        >
        > No matter wat the OO model is, I don't think the following code
        > exhibits sane behaviour:
        >
        > class A:
        > a = 1
        >
        > b = A()
        > b.a += 2
        > print b.a
        > print A.a
        >
        > Which results in
        >
        > 3
        > 1[/color]

        I find it confusing at first, but I do understand what happens :-)

        But really, what should be done different here?

        S.

        Comment

        • Steve Holden

          #5
          Re: Class Variable Access and Assignment

          Antoon Pardon wrote:[color=blue]
          > Op 2005-11-03, Steven D'Aprano schreef <steve@REMOVETH IScyber.com.au> :
          >
          >[color=green][color=darkred]
          >>>There are two possible fixes, either by prohibiting instance variables
          >>>with the same name as class variables, which would allow any reference
          >>>to an instance of the class assign/read the value of the variable. Or
          >>>to only allow class variables to be accessed via the class name itself.[/color]
          >>
          >>There is also a third fix: understand Python's OO model, especially
          >>inheritance , so that normal behaviour no longer surprises you.[/color]
          >
          >
          > No matter wat the OO model is, I don't think the following code
          > exhibits sane behaviour:
          >
          > class A:
          > a = 1
          >
          > b = A()
          > b.a += 2
          > print b.a
          > print A.a
          >
          > Which results in
          >
          > 3
          > 1
          >[/color]
          I don't suppose you'd care to enlighten us on what you'd regard as the
          superior outcome?

          regards
          Steve
          --
          Steve Holden +44 150 684 7255 +1 800 494 3119
          Holden Web LLC www.holdenweb.com
          PyCon TX 2006 www.python.org/pycon/

          Comment

          • Antoon Pardon

            #6
            Re: Class Variable Access and Assignment

            Op 2005-11-03, Stefan Arentz schreef <stefan.arentz@ gmail.com>:[color=blue]
            > Antoon Pardon <apardon@forel. vub.ac.be> writes:
            >[color=green]
            >> Op 2005-11-03, Steven D'Aprano schreef <steve@REMOVETH IScyber.com.au> :
            >>[color=darkred]
            >> >> There are two possible fixes, either by prohibiting instance variables
            >> >> with the same name as class variables, which would allow any reference
            >> >> to an instance of the class assign/read the value of the variable. Or
            >> >> to only allow class variables to be accessed via the class name itself.
            >> >
            >> > There is also a third fix: understand Python's OO model, especially
            >> > inheritance, so that normal behaviour no longer surprises you.[/color]
            >>
            >> No matter wat the OO model is, I don't think the following code
            >> exhibits sane behaviour:
            >>
            >> class A:
            >> a = 1
            >>
            >> b = A()
            >> b.a += 2
            >> print b.a
            >> print A.a
            >>
            >> Which results in
            >>
            >> 3
            >> 1[/color]
            >
            > I find it confusing at first, but I do understand what happens :-)[/color]

            I understand what happens too, that doesn't make it sane behaviour.
            [color=blue]
            > But really, what should be done different here?[/color]

            I don't care what should be different. But a line with only one
            referent to an object in it, shouldn't be referring to two different
            objects.

            In the line: b.a += 2, the b.a should be refering to the class variable
            or the object variable but not both. So either it could raise an
            attribute error or add two to the class variable.

            Sure one could object to those sematics too, but IMO they are preferable
            to what we have now.

            --
            Antoon Pardon

            Comment

            • Paul Rubin

              #7
              Re: Class Variable Access and Assignment

              Steve Holden <steve@holdenwe b.com> writes:[color=blue][color=green]
              > > class A:
              > > a = 1
              > > b = A()
              > > b.a += 2
              > > print b.a
              > > print A.a
              > > Which results in
              > > 3
              > > 1
              > >[/color]
              > I don't suppose you'd care to enlighten us on what you'd regard as the
              > superior outcome?[/color]

              class A:
              a = []
              b = A()
              b.append(3)
              print b.a
              print a.a

              Compare and contrast.

              Comment

              • Steven D'Aprano

                #8
                Re: Class Variable Access and Assignment

                On Thu, 03 Nov 2005 11:55:06 +0000, Antoon Pardon wrote:
                [color=blue]
                > No matter wat the OO model is, I don't think the following code
                > exhibits sane behaviour:
                >
                > class A:
                > a = 1
                >
                > b = A()
                > b.a += 2
                > print b.a
                > print A.a
                >
                > Which results in
                >
                > 3
                > 1[/color]

                Seems perfectly sane to me.

                What would you expect to get if you wrote b.a = b.a + 2? Why do you expect
                b.a += 2 to give a different result?

                Since ints are immutable objects, you shouldn't expect the value of b.a
                to be modified in place, and so there is an assignment to b.a, not A.a.

                On the other hand, if this happened:

                py> class A:
                .... a = []
                ....
                py> b = A()
                py> b.a.append(None )
                py> print b.a, A.a
                [None], []

                *then* you should be surprised.

                (Note that this is not what happens: you get [None], [None] as expected.
                The difference is that append modifies the mutable list in place.)



                --
                Steven.

                Comment

                • Stefan Arentz

                  #9
                  Re: Class Variable Access and Assignment

                  Antoon Pardon <apardon@forel. vub.ac.be> writes:

                  ....
                  [color=blue][color=green][color=darkred]
                  > >> No matter wat the OO model is, I don't think the following code
                  > >> exhibits sane behaviour:
                  > >>
                  > >> class A:
                  > >> a = 1
                  > >>
                  > >> b = A()
                  > >> b.a += 2
                  > >> print b.a
                  > >> print A.a
                  > >>
                  > >> Which results in
                  > >>
                  > >> 3
                  > >> 1[/color]
                  > >
                  > > I find it confusing at first, but I do understand what happens :-)[/color]
                  >
                  > I understand what happens too, that doesn't make it sane behaviour.
                  >[color=green]
                  > > But really, what should be done different here?[/color]
                  >
                  > I don't care what should be different. But a line with only one
                  > referent to an object in it, shouldn't be referring to two different
                  > objects.[/color]

                  It doesn't.
                  [color=blue]
                  > In the line: b.a += 2, the b.a should be refering to the class variable
                  > or the object variable but not both. So either it could raise an
                  > attribute error or add two to the class variable.[/color]

                  It does exactly what you say. It adds 2 to the a *instance variable* of
                  the object instance in 'b'. It doesn't touch the *class variable* A.a
                  which is still 1.

                  S.

                  Comment

                  • Steve Holden

                    #10
                    Re: Class Variable Access and Assignment

                    Paul Rubin wrote:[color=blue]
                    > Steve Holden <steve@holdenwe b.com> writes:
                    >[color=green][color=darkred]
                    >>>class A:
                    >>> a = 1
                    >>>b = A()
                    >>>b.a += 2
                    >>>print b.a
                    >>>print A.a
                    >>>Which results in
                    >>>3
                    >>>1
                    >>>[/color]
                    >>
                    >>I don't suppose you'd care to enlighten us on what you'd regard as the
                    >>superior outcome?[/color]
                    >
                    >
                    > class A:
                    > a = []
                    > b = A()
                    > b.append(3)
                    > print b.a
                    > print a.a
                    >
                    > Compare and contrast.[/color]

                    append() guarantees to modify a mutable object in place. Augmented
                    assignment operations don't,but are "normally" equivalent to

                    name = name operator value

                    In the former case exactly such semantics are implemented. I still don;t
                    see anyone suggesting a better outcome for the augmented assignment.

                    regards
                    Steve
                    --
                    Steve Holden +44 150 684 7255 +1 800 494 3119
                    Holden Web LLC www.holdenweb.com
                    PyCon TX 2006 www.python.org/pycon/

                    Comment

                    • Antoon Pardon

                      #11
                      Re: Class Variable Access and Assignment

                      Op 2005-11-03, Stefan Arentz schreef <stefan.arentz@ gmail.com>:[color=blue]
                      > Antoon Pardon <apardon@forel. vub.ac.be> writes:
                      >
                      > ...
                      >[color=green][color=darkred]
                      >> >> No matter wat the OO model is, I don't think the following code
                      >> >> exhibits sane behaviour:
                      >> >>
                      >> >> class A:
                      >> >> a = 1
                      >> >>
                      >> >> b = A()
                      >> >> b.a += 2
                      >> >> print b.a
                      >> >> print A.a
                      >> >>
                      >> >> Which results in
                      >> >>
                      >> >> 3
                      >> >> 1
                      >> >
                      >> > I find it confusing at first, but I do understand what happens :-)[/color]
                      >>
                      >> I understand what happens too, that doesn't make it sane behaviour.
                      >>[color=darkred]
                      >> > But really, what should be done different here?[/color]
                      >>
                      >> I don't care what should be different. But a line with only one
                      >> referent to an object in it, shouldn't be referring to two different
                      >> objects.[/color]
                      >
                      > It doesn't.[/color]

                      Yes it does. If the b.a refers to the instance variable, then an
                      AttributeError should be raised, because the instance variable doesn't
                      exist yet, so you can't add two to it.

                      If the b.a refers to the class variable then two should be added to it.

                      Neither happens instead we get some hybrid in which an instance varible
                      is created that gets the value of class variable incrented by two.
                      [color=blue][color=green]
                      >> In the line: b.a += 2, the b.a should be refering to the class variable
                      >> or the object variable but not both. So either it could raise an
                      >> attribute error or add two to the class variable.[/color]
                      >
                      > It does exactly what you say. It adds 2 to the a *instance variable* of
                      > the object instance in 'b'.[/color]

                      There is no instance variable at that point. How can it add 2, to
                      something that doesn't exist at the moment.
                      [color=blue]
                      > It doesn't touch the *class variable* A.a which is still 1.[/color]

                      But it accesses the class variable.

                      --
                      Antoon Pardon

                      Comment

                      • Antoon Pardon

                        #12
                        Re: Class Variable Access and Assignment

                        Op 2005-11-03, Steve Holden schreef <steve@holdenwe b.com>:[color=blue]
                        > Antoon Pardon wrote:[color=green]
                        >> Op 2005-11-03, Steven D'Aprano schreef <steve@REMOVETH IScyber.com.au> :
                        >>
                        >>[color=darkred]
                        >>>>There are two possible fixes, either by prohibiting instance variables
                        >>>>with the same name as class variables, which would allow any reference
                        >>>>to an instance of the class assign/read the value of the variable. Or
                        >>>>to only allow class variables to be accessed via the class name itself.
                        >>>
                        >>>There is also a third fix: understand Python's OO model, especially
                        >>>inheritanc e, so that normal behaviour no longer surprises you.[/color]
                        >>
                        >>
                        >> No matter wat the OO model is, I don't think the following code
                        >> exhibits sane behaviour:
                        >>
                        >> class A:
                        >> a = 1
                        >>
                        >> b = A()
                        >> b.a += 2
                        >> print b.a
                        >> print A.a
                        >>
                        >> Which results in
                        >>
                        >> 3
                        >> 1
                        >>[/color]
                        > I don't suppose you'd care to enlighten us on what you'd regard as the
                        > superior outcome?[/color]

                        No. I don't think a superior outcome is necessary to see that this is
                        not sane behaviour. I don't care that much on how it gets fixed.

                        --
                        Antoon Pardon

                        Comment

                        • Antoon Pardon

                          #13
                          Re: Class Variable Access and Assignment

                          Op 2005-11-03, Steven D'Aprano schreef <steve@REMOVETH IScyber.com.au> :[color=blue]
                          > On Thu, 03 Nov 2005 11:55:06 +0000, Antoon Pardon wrote:
                          >[color=green]
                          >> No matter wat the OO model is, I don't think the following code
                          >> exhibits sane behaviour:
                          >>
                          >> class A:
                          >> a = 1
                          >>
                          >> b = A()
                          >> b.a += 2
                          >> print b.a
                          >> print A.a
                          >>
                          >> Which results in
                          >>
                          >> 3
                          >> 1[/color]
                          >
                          > Seems perfectly sane to me.
                          >
                          > What would you expect to get if you wrote b.a = b.a + 2?[/color]

                          I would expect a result consistent with the fact that both times
                          b.a would refer to the same object.
                          [color=blue]
                          > Why do you expect
                          > b.a += 2 to give a different result?[/color]

                          I didn't know I did.
                          [color=blue]
                          > Since ints are immutable objects, you shouldn't expect the value of b.a
                          > to be modified in place, and so there is an assignment to b.a, not A.a.[/color]

                          You are now talking implementation details. I don't care about whatever
                          explanation you give in terms of implementation details. I don't think
                          it is sane that in a language multiple occurence of something like b.a
                          in the same line can refer to different objects

                          I think it even less sane, if the same occurce of b.a refers to two
                          different objects, like in b.a += 2

                          --
                          Antoon Pardon.

                          Comment

                          • venk

                            #14
                            Re: Class Variable Access and Assignment

                            You see,
                            The seen behavior is due to the result of python's name
                            binding,scoping scheme.
                            Let me give you an example,
                            class A:
                            i=0
                            def t(self):
                            print self.i
                            self.i=4
                            then
                            a=A()
                            a.i is 0
                            a.t()
                            then,
                            A.i is 0
                            a.i is 4

                            In the function, it first searches for i in its local scope, on not
                            finding it, accesses the class object's i.
                            then the next line, is an assignment, which binds (creates a new
                            variable) in the instance's scope. you can use the buit-in id function
                            to verify it.

                            the same thing happens in the case of b.a = b.a + 2 .... search for b.a
                            not found, read the value from the enclosing scope (of the class
                            object).... then assign b.a to the local scope, with the value 3.

                            But, I think your question about the sanity of the behaviour should be
                            analysed sincerely....

                            if,
                            k=0
                            def f():
                            print k
                            k=k+1
                            raises UnboundLocalErr or, then how is it accepted in the former case?
                            hmmm....

                            maybe, my arguments are hapazard.... but, i'll get to know when i'm
                            flamed ;)

                            Comment

                            • Sybren Stuvel

                              #15
                              Re: Class Variable Access and Assignment

                              Antoon Pardon enlightened us with:[color=blue]
                              > I would expect a result consistent with the fact that both times b.a
                              > would refer to the same object.[/color]

                              "b.a" is just a name, not a pointer to a spot in memory. Getting the
                              value associated with that name is something different from assigning
                              a new value to that name.

                              Sybren
                              --
                              The problem with the world is stupidity. Not saying there should be a
                              capital punishment for stupidity, but why don't we just take the
                              safety labels off of everything and let the problem solve itself?
                              Frank Zappa

                              Comment

                              Working...